Initial prototype of the V3 manifest extension (#4357)
* Initial prototype of the V3 manifest extension * Make sure the content script is only injected once * Implement addNote button * More separation work for tasks, implement archive and update note * Add back missing functionality, add guide to install Extensions * Revert v2 changes --------- Co-authored-by: Thomas Rogers <Podginator@gmail.com>
BIN
docs/guides/images/1-extension-page.png
Normal file
|
After Width: | Height: | Size: 211 KiB |
BIN
docs/guides/images/10-omnivore-api-keys.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
docs/guides/images/11-generate-key.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
docs/guides/images/12-copy-key.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
docs/guides/images/13-update-settings.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
docs/guides/images/2-developer-mode.png
Normal file
|
After Width: | Height: | Size: 201 KiB |
BIN
docs/guides/images/3-load-unpacked.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
docs/guides/images/4-folder.png
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
docs/guides/images/5-folders.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
docs/guides/images/6-installed.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
docs/guides/images/7-options.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/guides/images/8-options-page.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
docs/guides/images/9-omnivore-settings.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
26
pkg/extension-v3/Makefile
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
all: firefox chrome edge
|
||||||
|
|
||||||
|
build: *
|
||||||
|
rm -rf extension
|
||||||
|
yarn build
|
||||||
|
|
||||||
|
firefox:
|
||||||
|
echo "building firefox package"
|
||||||
|
rm -rf extension
|
||||||
|
yarn build
|
||||||
|
FIREFOX_PKG_NAME="firefox-$(shell cat extension/manifest.json| jq -j .version).zip" ; \
|
||||||
|
FIREFOX_SRC_NAME="firefox-$(shell cat extension/manifest.json| jq -j .version)-src.zip" ; \
|
||||||
|
cd extension; zip -r ../$$FIREFOX_PKG_NAME *; cd ..;\
|
||||||
|
zip -r $$FIREFOX_SRC_NAME src/* Makefile yarn.lock package.json; \
|
||||||
|
echo "done"
|
||||||
|
|
||||||
|
chrome: build
|
||||||
|
echo "building chrome package"
|
||||||
|
zip -r chrome-$(shell cat dist/manifest.json| jq -j .version).zip ./dist/*
|
||||||
|
|
||||||
|
edge: build
|
||||||
|
echo "building edge package"
|
||||||
|
EDGE_PKG_NAME="omnivore-extension-edge-$(shell cat dist/manifest.json| jq -j .version).zip" ; \
|
||||||
|
pushd dist; zip -r $${EDGE_PKG_NAME} ./*; popd;
|
||||||
|
|
||||||
|
|
||||||
1
pkg/extension-v3/extension/background.js
Normal file
1
pkg/extension-v3/extension/content.js
Normal file
BIN
pkg/extension-v3/extension/icons/icon-128.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
pkg/extension-v3/extension/icons/icon-16.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/extension-v3/extension/icons/icon-19.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pkg/extension-v3/extension/icons/icon-24.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
pkg/extension-v3/extension/icons/icon-256.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
pkg/extension-v3/extension/icons/icon-32.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
pkg/extension-v3/extension/icons/icon-38.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
pkg/extension-v3/extension/icons/icon-48.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
pkg/extension-v3/extension/icons/icon-70.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
pkg/extension-v3/extension/icons/icon-96.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
14
pkg/extension-v3/extension/images/highlight.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4278)">
|
||||||
|
<path d="M8 20.8342H11.3333L20.0833 12.0842C20.5254 11.6422 20.7737 11.0427 20.7737 10.4176C20.7737 9.79245 20.5254 9.19293 20.0833 8.7509C19.6413 8.30888 19.0418 8.06055 18.4167 8.06055C17.7915 8.06055 17.192 8.30888 16.75 8.7509L8 17.5009V20.8342Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.9166 9.58398L19.25 12.9173" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9.25 16.25L12.5833 19.5833" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M23 17.5V20.8333H16.3334L19.6667 17.5H23Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4278">
|
||||||
|
<rect width="20" height="20" fill="white" transform="translate(5.5 5)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
12
pkg/extension-v3/extension/images/label.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4271)">
|
||||||
|
<path d="M10.9166 12.2493C10.9166 12.4704 11.0044 12.6823 11.1607 12.8386C11.317 12.9949 11.5289 13.0827 11.75 13.0827C11.971 13.0827 12.1829 12.9949 12.3392 12.8386C12.4955 12.6823 12.5833 12.4704 12.5833 12.2493C12.5833 12.0283 12.4955 11.8164 12.3392 11.6601C12.1829 11.5038 11.971 11.416 11.75 11.416C11.5289 11.416 11.317 11.5038 11.1607 11.6601C11.0044 11.8164 10.9166 12.0283 10.9166 12.2493Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8 11V15.31C8.00009 15.752 8.17575 16.1758 8.48833 16.4883L14.9133 22.9133C15.29 23.2899 15.8007 23.5015 16.3333 23.5015C16.8659 23.5015 17.3767 23.2899 17.7533 22.9133L22.4133 18.2533C22.7899 17.8767 23.0015 17.3659 23.0015 16.8333C23.0015 16.3007 22.7899 15.79 22.4133 15.4133L15.9883 8.98833C15.6758 8.67575 15.252 8.50009 14.81 8.5H10.5C9.83696 8.5 9.20107 8.76339 8.73223 9.23223C8.26339 9.70107 8 10.337 8 11Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4271">
|
||||||
|
<rect width="20" height="20" fill="white" transform="translate(5.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
11
pkg/extension-v3/extension/images/listen-hover.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle class="circle-bg" cx="15.5" cy="15" r="15" fill="#6A6968"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4264)">
|
||||||
|
<path d="M11 9.00021V21.0002C11 21.1337 11.0355 21.2647 11.103 21.3798C11.1705 21.4949 11.2675 21.5899 11.384 21.6551C11.5005 21.7202 11.6322 21.753 11.7657 21.7503C11.8991 21.7475 12.0293 21.7091 12.143 21.6392L21.893 15.6392C22.0022 15.5721 22.0924 15.4781 22.1549 15.3663C22.2175 15.2544 22.2503 15.1284 22.2503 15.0002C22.2503 14.872 22.2175 14.746 22.1549 14.6341C22.0924 14.5223 22.0022 14.4283 21.893 14.3612L12.143 8.36121C12.0293 8.29128 11.8991 8.25295 11.7657 8.25016C11.6322 8.24738 11.5005 8.28024 11.384 8.34536C11.2675 8.41048 11.1705 8.50549 11.103 8.62061C11.0355 8.73572 11 8.86676 11 9.00021Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4264">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 976 B |
11
pkg/extension-v3/extension/images/listen.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle class="circle-bg" cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4264)">
|
||||||
|
<path d="M11 9.00021V21.0002C11 21.1337 11.0355 21.2647 11.103 21.3798C11.1705 21.4949 11.2675 21.5899 11.384 21.6551C11.5005 21.7202 11.6322 21.753 11.7657 21.7503C11.8991 21.7475 12.0293 21.7091 12.143 21.6392L21.893 15.6392C22.0022 15.5721 22.0924 15.4781 22.1549 15.3663C22.2175 15.2544 22.2503 15.1284 22.2503 15.0002C22.2503 14.872 22.2175 14.746 22.1549 14.6341C22.0924 14.5223 22.0022 14.4283 21.893 14.3612L12.143 8.36121C12.0293 8.29128 11.8991 8.25295 11.7657 8.25016C11.6322 8.24738 11.5005 8.28024 11.384 8.34536C11.2675 8.41048 11.1705 8.50549 11.103 8.62061C11.0355 8.73572 11 8.86676 11 9.00021Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4264">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 976 B |
3
pkg/extension-v3/extension/images/pause-w-circle.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M15.5076 30.1582C23.7381 30.1582 30.5 23.3963 30.5 15.1659C30.5 6.92006 23.7381 0.158203 15.4924 0.158203C7.26186 0.158203 0.5 6.92006 0.5 15.1659C0.5 23.3963 7.26186 30.1582 15.5076 30.1582ZM15.5076 28.9955C7.85849 28.9955 1.66267 22.7997 1.66267 15.1659C1.66267 7.53199 7.85849 1.32088 15.4924 1.32088C23.1415 1.32088 29.3373 7.53199 29.3373 15.1659C29.3373 22.7997 23.1415 28.9955 15.5076 28.9955ZM11.3465 20.918H12.9069C13.5342 20.918 13.8248 20.5662 13.8248 20.0613V10.2398C13.8248 9.73495 13.5342 9.38309 12.9069 9.38309H11.3465C10.7346 9.38309 10.4286 9.73495 10.4286 10.2398V20.0613C10.4286 20.5662 10.7346 20.918 11.3465 20.918ZM18.0931 20.918H19.6382C20.2501 20.918 20.5561 20.5662 20.5561 20.0613V10.2398C20.5561 9.73495 20.2501 9.38309 19.6382 9.38309H18.0931C17.4658 9.38309 17.1752 9.73495 17.1752 10.2398V20.0613C17.1752 20.5662 17.4658 20.918 18.0931 20.918Z" fill="#D9D9D9"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1005 B |
5
pkg/extension-v3/extension/images/playback-speed.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="31" height="32" viewBox="0 0 31 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="16.1582" r="15" fill="#3D3D3D"/>
|
||||||
|
<path d="M15.5 31.1582C13.5302 31.1582 11.5796 30.7702 9.75975 30.0164C7.93986 29.2626 6.28628 28.1577 4.8934 26.7648C3.50052 25.3719 2.39563 23.7183 1.64181 21.8985C0.887985 20.0786 0.499999 18.128 0.499999 16.1582C0.5 14.1884 0.887986 12.2378 1.64181 10.4179C2.39563 8.59807 3.50052 6.94448 4.8934 5.5516C6.28628 4.15872 7.93987 3.05383 9.75975 2.30001C11.5796 1.54619 13.5302 1.1582 15.5 1.1582C17.4698 1.1582 19.4204 1.54619 21.2403 2.30001C23.0601 3.05383 24.7137 4.15872 26.1066 5.5516C27.4995 6.94448 28.6044 8.59807 29.3582 10.418C30.112 12.2378 30.5 14.1884 30.5 16.1582C30.5 18.128 30.112 20.0786 29.3582 21.8985C28.6044 23.7183 27.4995 25.3719 26.1066 26.7648C24.7137 28.1577 23.0601 29.2626 21.2402 30.0164C19.4204 30.7702 17.4698 31.1582 15.5 31.1582L15.5 31.1582Z" stroke="#898989"/>
|
||||||
|
<path d="M8.26074 20.1582V14.4648H8.23145L6.43457 15.7051V14.377L8.25586 13.1123H9.7207V20.1582H8.26074ZM12.0693 20.2168C11.6299 20.2168 11.2832 19.8652 11.2832 19.4307C11.2832 18.9912 11.6299 18.6445 12.0693 18.6445C12.5039 18.6445 12.8555 18.9912 12.8555 19.4307C12.8555 19.8652 12.5039 20.2168 12.0693 20.2168ZM16.6299 20.3145C15.1162 20.3145 14.0273 19.416 13.9834 18.1416H15.3457C15.4287 18.7373 15.9561 19.1475 16.6396 19.1475C17.4111 19.1475 17.9434 18.6104 17.9434 17.8438C17.9434 17.0625 17.4111 16.5156 16.6494 16.5156C16.1172 16.5156 15.6582 16.7598 15.4141 17.165H14.0957L14.4424 13.1123H18.9248V14.2842H15.5996L15.4385 16.2129H15.4678C15.7559 15.7393 16.3174 15.4414 17.0352 15.4414C18.3828 15.4414 19.3496 16.4326 19.3496 17.8047C19.3496 19.2988 18.2461 20.3145 16.6299 20.3145ZM22.2402 18.3418H22.2109L21.2295 20.1582H19.7305L21.3711 17.5508L19.7402 14.9238H21.3467L22.2891 16.6914H22.3184L23.2461 14.9238H24.7988L23.1631 17.5117L24.7842 20.1582H23.2363L22.2402 18.3418Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
15
pkg/extension-v3/extension/images/playback-voice.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<svg width="31" height="32" viewBox="0 0 31 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="16.1582" r="15" fill="#3D3D3D"/>
|
||||||
|
<path d="M15.5 31.1582C13.5302 31.1582 11.5796 30.7702 9.75975 30.0164C7.93986 29.2626 6.28628 28.1577 4.8934 26.7648C3.50052 25.3719 2.39563 23.7183 1.64181 21.8985C0.887985 20.0786 0.499999 18.128 0.499999 16.1582C0.5 14.1884 0.887986 12.2378 1.64181 10.4179C2.39563 8.59807 3.50052 6.94448 4.8934 5.5516C6.28628 4.15872 7.93987 3.05383 9.75975 2.30001C11.5796 1.54619 13.5302 1.1582 15.5 1.1582C17.4698 1.1582 19.4204 1.54619 21.2403 2.30001C23.0601 3.05383 24.7137 4.15872 26.1066 5.5516C27.4995 6.94448 28.6044 8.59807 29.3582 10.418C30.112 12.2378 30.5 14.1884 30.5 16.1582C30.5 18.128 30.112 20.0786 29.3582 21.8985C28.6044 23.7183 27.4995 25.3719 26.1066 26.7648C24.7137 28.1577 23.0601 29.2626 21.2402 30.0164C19.4204 30.7702 17.4698 31.1582 15.5 31.1582L15.5 31.1582Z" stroke="#898989"/>
|
||||||
|
<g clip-path="url(#clip0_11902_5015)">
|
||||||
|
<path d="M18.1266 11.6096C17.9021 11.8338 17.902 12.1975 18.1263 12.4219C19.6353 13.932 19.6344 16.39 18.1241 17.9011C17.8999 18.1256 17.9 18.4892 18.1243 18.7135C18.2366 18.8256 18.3835 18.8817 18.5305 18.8817C18.6776 18.8817 18.8247 18.8255 18.9369 18.7133C20.8945 16.7543 20.8955 13.5678 18.939 11.6098C18.7148 11.3854 18.351 11.3852 18.1266 11.6096Z" fill="white"/>
|
||||||
|
<path d="M15.979 13.2581C15.7545 13.4822 15.7544 13.846 15.9787 14.0704C16.5803 14.6725 16.5802 15.6521 15.9786 16.2541C15.7543 16.4785 15.7544 16.8422 15.9789 17.0665C16.091 17.1786 16.238 17.2346 16.3849 17.2346C16.532 17.2346 16.6791 17.1785 16.7913 17.0662C17.8404 16.0164 17.8404 14.3081 16.7914 13.2583C16.5672 13.0338 16.2034 13.0337 15.979 13.2581Z" fill="white"/>
|
||||||
|
<path d="M21.4821 9.06494C21.2578 8.84045 20.8941 8.84033 20.6697 9.0646C20.4452 9.28886 20.4451 9.65261 20.6694 9.87699C23.5803 12.7897 23.579 17.5303 20.6665 20.4444C20.4421 20.6687 20.4423 21.0325 20.6667 21.2567C20.7789 21.3688 20.9258 21.4249 21.0728 21.4249C21.2198 21.4249 21.367 21.3687 21.4791 21.2565C24.8392 17.8946 24.8405 12.4254 21.4821 9.06494Z" fill="white"/>
|
||||||
|
<path d="M11.1793 18.8664C12.6562 18.7646 13.8271 17.5299 13.8271 16.0258C13.8271 14.4553 12.5508 13.1777 10.9821 13.1777C9.4133 13.1777 8.13699 14.4553 8.13699 16.0258C8.13699 17.5298 9.30775 18.7645 10.7848 18.8664C9.67895 18.9089 8.70503 19.3084 8.02629 20.0031C7.32894 20.7169 6.97457 21.705 7.00142 22.861C7.00869 23.1729 7.26363 23.4221 7.5757 23.4221H14.3878C14.6999 23.4221 14.9549 23.1729 14.9621 22.8609C14.989 21.7049 14.6345 20.7166 13.9371 20.0029C13.2585 19.3083 12.2849 18.9089 11.1793 18.8664ZM9.28589 16.0258C9.28589 15.0889 10.0468 14.3266 10.9821 14.3266C11.9173 14.3266 12.6782 15.0889 12.6782 16.0258C12.6782 16.9628 11.9173 17.7251 10.9821 17.7251C10.0468 17.7251 9.28589 16.9628 9.28589 16.0258ZM8.17677 22.2731C8.25158 21.6784 8.4763 21.1866 8.84812 20.8061C9.34897 20.2935 10.1068 20.0112 10.9819 20.0112C11.857 20.0112 12.6146 20.2934 13.1154 20.8059C13.4871 21.1863 13.712 21.6783 13.7867 22.2731H8.17677Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11902_5015">
|
||||||
|
<rect width="17" height="17" fill="white" transform="translate(7 7.6582)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
11
pkg/extension-v3/extension/images/save.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4287)">
|
||||||
|
<path d="M17 7.5C17.9946 7.5 18.9484 7.89509 19.6517 8.59835C20.3549 9.30161 20.75 10.2554 20.75 11.25V21.75C20.75 21.8858 20.7132 22.019 20.6434 22.1355C20.5736 22.252 20.4735 22.3473 20.3538 22.4114C20.2341 22.4755 20.0992 22.5058 19.9636 22.4992C19.828 22.4926 19.6967 22.4494 19.5837 22.374L15.5 19.6515L11.417 22.374C11.31 22.4456 11.1863 22.4885 11.0579 22.4985C10.9295 22.5084 10.8007 22.4852 10.6839 22.4309C10.5671 22.3766 10.4662 22.2932 10.391 22.1887C10.3158 22.0841 10.2688 21.962 10.2545 21.834L10.25 21.75V11.25C10.25 10.2554 10.6451 9.30161 11.3483 8.59835C12.0516 7.89509 13.0054 7.5 14 7.5H17Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4287">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 958 B |
42
pkg/extension-v3/extension/manifest.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Omnivore - Self Hosted",
|
||||||
|
"version": "3.0",
|
||||||
|
"description": "Save content to your Omnivore library.",
|
||||||
|
"permissions": [
|
||||||
|
"activeTab",
|
||||||
|
"scripting",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"host_permissions": [
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"background": {
|
||||||
|
"service_worker": "background.js",
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"web_accessible_resources": [
|
||||||
|
{
|
||||||
|
"resources": [
|
||||||
|
"images/*.svg",
|
||||||
|
"views/toast.html"
|
||||||
|
],
|
||||||
|
"matches": [
|
||||||
|
"<all_urls>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options_page": "views/options.html",
|
||||||
|
"action": {
|
||||||
|
"default_icon": {
|
||||||
|
"16": "icons/icon-16.png",
|
||||||
|
"48": "icons/icon-48.png",
|
||||||
|
"128": "icons/icon-128.png"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"icons": {
|
||||||
|
"16": "icons/icon-16.png",
|
||||||
|
"48": "icons/icon-48.png",
|
||||||
|
"128": "icons/icon-128.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
pkg/extension-v3/extension/toolbar.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
(()=>{"use strict";var r={322:(r,e,t)=>{t(454),t(782)},782:(r,e,t)=>{t(454),t(322)},454:(r,e,t)=>{}},e={};function t(o){var n=e[o];if(void 0!==n)return n.exports;var p=e[o]={exports:{}};return r[o](p,p.exports,t),p.exports}t.d=(r,e)=>{for(var o in e)t.o(e,o)&&!t.o(r,o)&&Object.defineProperty(r,o,{enumerable:!0,get:e[o]})},t.o=(r,e)=>Object.prototype.hasOwnProperty.call(r,e),t(782)})();
|
||||||
36
pkg/extension-v3/extension/views/options.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Omnivore Extension Settings</title>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class='wrapper'>
|
||||||
|
<h1>API Key</h1>
|
||||||
|
|
||||||
|
<label for="api-key">API Key:</label>
|
||||||
|
|
||||||
|
<input type="text" id="api-key" style="width: 95%">
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<button id="save-api-key-btn">Save API Key</button>
|
||||||
|
|
||||||
|
|
||||||
|
<h1>API URL</h1>
|
||||||
|
|
||||||
|
<label for="api-url">API URL:</label>
|
||||||
|
<input type="text" id="api-url" style="width: 95%">
|
||||||
|
<br><br>
|
||||||
|
<button id="save-api-url-btn">Save API URL</button>
|
||||||
|
|
||||||
|
<h1>OMNIVORE URL</h1>
|
||||||
|
|
||||||
|
<label for="omnivore-url">API URL:</label>
|
||||||
|
<input type="text" id="omnivore-url" style="width: 95%">
|
||||||
|
<br><br>
|
||||||
|
<button id="save-omnivore-url-btn">Save Omnivore URL</button>
|
||||||
|
|
||||||
|
<script src="options.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1
pkg/extension-v3/extension/views/options.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
function addStorage(e){return chrome.storage.local.set(e)}document.addEventListener("DOMContentLoaded",(()=>{const e=document.getElementById("save-api-key-btn"),t=document.getElementById("api-key");chrome.storage.local.get("omnivoreApiKey").then((e=>{t.value=e.omnivoreApiKey??""})),e.addEventListener("click",(e=>{addStorage({omnivoreApiKey:t.value})}));const o=document.getElementById("save-api-url-btn"),n=document.getElementById("api-url");chrome.storage.local.get("omnivoreApiUrl").then((e=>{n.value=e.omnivoreApiUrl??""})),o.addEventListener("click",(e=>{addStorage({omnivoreApiUrl:n.value})}));const r=document.getElementById("save-omnivore-url-btn"),a=document.getElementById("omnivore-url");chrome.storage.local.get("omnivoreUrl").then((e=>{a.value=e.omnivoreUrl??""})),r.addEventListener("click",(e=>{addStorage({omnivoreUrl:a.value})}))}));
|
||||||
555
pkg/extension-v3/extension/views/toast.html
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
<style>
|
||||||
|
#omnivore-toast-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #3D3D3D;
|
||||||
|
background: #fff;
|
||||||
|
font: 400 12px sans-serif;
|
||||||
|
line-height: 20px;
|
||||||
|
box-shadow: 0px 5px 20px rgba(32, 31, 29, 0.12);
|
||||||
|
transition: all 300ms ease;
|
||||||
|
z-index: 9999999;
|
||||||
|
width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container input, select, textarea{
|
||||||
|
color: #3D3D3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button {
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-logged-out-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row[data-state="open"] {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row[data-state="closed"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
color:#898989;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-status {
|
||||||
|
height: 22px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-button-row {
|
||||||
|
gap: 5px;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #898989;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
height: 30px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button:hover {
|
||||||
|
color: #3B3A38;
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-save-button button {
|
||||||
|
background-color: rgb(255, 210, 52)
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn:hover {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn svg {
|
||||||
|
fill: #3D3D3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn:hover > svg *,
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn svg:hover {
|
||||||
|
fill: #D9D9D9;
|
||||||
|
stroke: white;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container svg {
|
||||||
|
fill: #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container > svg *,
|
||||||
|
#omnivore-toast-container svg:hover {
|
||||||
|
fill: #3B3A38;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-edit-title-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-delete-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container form {
|
||||||
|
display: block;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.omnivore-toast-divider {
|
||||||
|
height:20px;
|
||||||
|
border-right: 1px solid #D9D9D9;
|
||||||
|
}
|
||||||
|
.omnivore-toast-statusBox {
|
||||||
|
display: flex;
|
||||||
|
width: 20px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-title-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-title-row textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
padding: 5px;
|
||||||
|
resize: none;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
padding: 5px;
|
||||||
|
resize: none;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row button {
|
||||||
|
height: 30px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-left: auto;
|
||||||
|
background-color: #FFEA9F;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row input {
|
||||||
|
width: 100%;
|
||||||
|
height: 34px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-extra-buttons-row {
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button {
|
||||||
|
align-self: flex-start;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-list {
|
||||||
|
overflow-y: scroll;
|
||||||
|
max-height: 200px;
|
||||||
|
gap: 5px;
|
||||||
|
color: #3B3A38;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
height: 35px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
background: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button[data-label-selected="on"] .checkbox {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button[data-label-selected="off"] .checkbox {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:focus-visible {
|
||||||
|
outline: unset;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-list div:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
#omnivore-edit-labels-row form {
|
||||||
|
margin-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row input, select, textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#omnivore-edit-title-row textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.omnivore-toast-menu-divider {
|
||||||
|
border-bottom: 1px solid #D9D9D9;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-login-btn {
|
||||||
|
color: #898989;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
#omnivore-toast-container {
|
||||||
|
background: #333333;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container input, select, textarea{
|
||||||
|
color: #D9D9D9;
|
||||||
|
}
|
||||||
|
.omnivore-toast-divider {
|
||||||
|
border-right: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container svg {
|
||||||
|
fill: #898989;
|
||||||
|
}
|
||||||
|
.omnivore-save-button button {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button:hover > svg *,
|
||||||
|
#omnivore-toast-container button:hover {
|
||||||
|
color: #D9D9D9;
|
||||||
|
fill: #D9D9D9;
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:hover {
|
||||||
|
color: #D9D9D9;
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button:hover {
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
border-bottom: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-edit-title-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-delete-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
.omnivore-toast-menu-divider {
|
||||||
|
border-bottom: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-login-btn {
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.label-editor {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
background-color: var(--colors-thBackground2);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px;
|
||||||
|
line-height: 2;
|
||||||
|
cursor: text;
|
||||||
|
font-size: 12px;
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-list {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: start;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: auto;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row .label-remove-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: transparent;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row .label-input {
|
||||||
|
box-sizing: content-box;
|
||||||
|
font-size: 16px;
|
||||||
|
min-width: 2px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
padding: 0px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: inline-table;
|
||||||
|
padding: 1px;
|
||||||
|
padding-left: 7px;
|
||||||
|
padding-right: 7px;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
border: 1px solid rgb(222, 222, 222);
|
||||||
|
background-color: rgb(249, 249, 249);
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row .label button {
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label[data-label-backspaced="on"] {
|
||||||
|
border: 1px solid rgb(255, 234, 159);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label[data-item-highlighted="on"] {
|
||||||
|
border: 1px solid black;
|
||||||
|
transition: border-color 0.25s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
/* control spinner size with setting font-size */
|
||||||
|
font-size: 3rem;
|
||||||
|
border: 2px solid #FFD234;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
animation: loading-spinner 1.5s linear infinite;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading-spinner {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<div id="omnivore-toast-container">
|
||||||
|
<div id="omnivore-toast-button-row">
|
||||||
|
<span class="omnivore-toast-statusBox">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
</span>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button class="omnivore-top-button" id="omnivore-toast-add-note-btn">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 256 256">
|
||||||
|
<path d="M88,96a8,8,0,0,1,8-8h64a8,8,0,0,1,0,16H96A8,8,0,0,1,88,96Zm8,40h64a8,8,0,0,0,0-16H96a8,8,0,0,0,0,16Zm32,16H96a8,8,0,0,0,0,16h32a8,8,0,0,0,0-16ZM224,48V156.69A15.86,15.86,0,0,1,219.31,168L168,219.31A15.86,15.86,0,0,1,156.69,224H48a16,16,0,0,1-16-16V48A16,16,0,0,1,48,32H208A16,16,0,0,1,224,48ZM48,208H152V160a8,8,0,0,1,8-8h48V48H48Zm120-40v28.7L196.69,168Z"></path>
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Add Note</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-edit-labels-btn">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.99031 14.9786L15.3061 8.67029C15.3757 8.6002 15.4307 8.51707 15.468 8.42568C15.5053 8.33429 15.5242 8.23643 15.5237 8.13772L15.5237 1.38683C15.5237 1.18789 15.4446 0.997101 15.304 0.85643C15.1633 0.715759 14.9725 0.636731 14.7736 0.636731L8.02269 0.636731C7.92397 0.63616 7.82611 0.655082 7.73472 0.69241C7.64333 0.729738 7.5602 0.784739 7.49012 0.85426L1.18179 7.17009C0.76038 7.59202 0.523681 8.16397 0.523681 8.7603C0.523681 9.35663 0.76038 9.92857 1.18179 10.3505L5.77239 14.9786C6.19432 15.4 6.76627 15.6367 7.3626 15.6367C7.95893 15.6367 8.53087 15.4 8.95281 14.9786L8.99031 14.9786ZM6.87503 13.921L2.24693 9.28536C2.10722 9.14482 2.0288 8.95471 2.0288 8.75655C2.0288 8.55838 2.10722 8.36827 2.24693 8.22773L8.33022 2.13693L14.0235 2.13693L14.0235 7.83018L7.93267 13.921C7.86258 13.9905 7.77946 14.0455 7.68807 14.0828C7.59668 14.1202 7.49882 14.1391 7.4001 14.1385C7.20332 14.1377 7.01475 14.0595 6.87503 13.921Z" />
|
||||||
|
<circle cx="10.8818" cy="5.48069" r="1.24925" />
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Set Labels</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-read-now-btn">
|
||||||
|
<svg width="18" height="15" viewBox="0 0 18 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.1272 0.939454H12.6584C11.6995 0.939454 10.762 1.21484 9.95532 1.73438L9.0022 2.3457L8.04907 1.73438C7.24323 1.21494 6.30469 0.938941 5.34595 0.939454H0.877197C0.531494 0.939454 0.252197 1.21875 0.252197 1.56445V12.6582C0.252197 13.0039 0.531494 13.2832 0.877197 13.2832H5.34595C6.30493 13.2832 7.24243 13.5586 8.04907 14.0781L8.91626 14.6367C8.94165 14.6523 8.97095 14.6621 9.00024 14.6621C9.02954 14.6621 9.05884 14.6543 9.08423 14.6367L9.95142 14.0781C10.76 13.5586 11.6995 13.2832 12.6584 13.2832H17.1272C17.4729 13.2832 17.7522 13.0039 17.7522 12.6582V1.56445C17.7522 1.21875 17.4729 0.939454 17.1272 0.939454ZM5.34595 11.877H1.65845V2.3457H5.34595C6.03735 2.3457 6.70923 2.54297 7.28931 2.91602L8.24243 3.52734L8.3772 3.61523V12.6387C7.44751 12.1387 6.40845 11.877 5.34595 11.877ZM16.3459 11.877H12.6584C11.5959 11.877 10.5569 12.1387 9.6272 12.6387V3.61523L9.76196 3.52734L10.7151 2.91602C11.2952 2.54297 11.967 2.3457 12.6584 2.3457H16.3459V11.877ZM6.75415 4.8457H3.12524C3.04907 4.8457 2.98657 4.91211 2.98657 4.99219V5.87109C2.98657 5.95117 3.04907 6.01758 3.12524 6.01758H6.7522C6.82837 6.01758 6.89087 5.95117 6.89087 5.87109V4.99219C6.89282 4.91211 6.83032 4.8457 6.75415 4.8457ZM11.1116 4.99219V5.87109C11.1116 5.95117 11.1741 6.01758 11.2502 6.01758H14.8772C14.9534 6.01758 15.0159 5.95117 15.0159 5.87109V4.99219C15.0159 4.91211 14.9534 4.8457 14.8772 4.8457H11.2502C11.1741 4.8457 11.1116 4.91211 11.1116 4.99219ZM6.75415 7.58008H3.12524C3.04907 7.58008 2.98657 7.64648 2.98657 7.72656V8.60547C2.98657 8.68555 3.04907 8.75195 3.12524 8.75195H6.7522C6.82837 8.75195 6.89087 8.68555 6.89087 8.60547V7.72656C6.89282 7.64648 6.83032 7.58008 6.75415 7.58008ZM14.8792 7.58008H11.2502C11.1741 7.58008 11.1116 7.64648 11.1116 7.72656V8.60547C11.1116 8.68555 11.1741 8.75195 11.2502 8.75195H14.8772C14.9534 8.75195 15.0159 8.68555 15.0159 8.60547V7.72656C15.0178 7.64648 14.9553 7.58008 14.8792 7.58008Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Read Now</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-open-menu-btn">
|
||||||
|
<svg width="15" height="4" viewBox="0 0 15 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<ellipse cx="1.48679" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="7.00217" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="7.00217" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="12.5176" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-close-btn">
|
||||||
|
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="9.50049" cy="9.52783" r="9" />
|
||||||
|
<path d="M12.554 11.874L12.554 11.874L10.2075 9.52783L12.554 7.18165L12.554 7.18164C12.6478 7.08785 12.7005 6.96063 12.7005 6.82798C12.7005 6.69533 12.6478 6.56812 12.554 6.47432C12.4602 6.38053 12.333 6.32783 12.2003 6.32783C12.0677 6.32783 11.9405 6.38053 11.8467 6.47432L11.8467 6.47433L9.50049 8.82087L7.15431 6.47433L7.1543 6.47432C7.0605 6.38053 6.93329 6.32783 6.80064 6.32783C6.66799 6.32783 6.54078 6.38053 6.44698 6.47432C6.35318 6.56812 6.30049 6.69533 6.30049 6.82798C6.30049 6.96063 6.35318 7.08785 6.44698 7.18164L6.44699 7.18165L8.79352 9.52783L6.44699 11.874L6.44698 11.874C6.35318 11.9678 6.30049 12.095 6.30049 12.2277C6.30049 12.3603 6.35318 12.4875 6.44698 12.5813C6.54078 12.6751 6.66799 12.7278 6.80064 12.7278C6.93329 12.7278 7.0605 12.6751 7.1543 12.5813L7.15431 12.5813L9.50049 10.2348L11.8467 12.5813L11.8467 12.5813C11.8931 12.6278 11.9483 12.6646 12.0089 12.6898C12.0696 12.7149 12.1347 12.7278 12.2003 12.7278C12.266 12.7278 12.3311 12.7149 12.3917 12.6898C12.4524 12.6646 12.5076 12.6278 12.554 12.5813C12.6004 12.5349 12.6373 12.4798 12.6624 12.4191C12.6876 12.3584 12.7005 12.2934 12.7005 12.2277C12.7005 12.162 12.6876 12.097 12.6624 12.0363C12.6373 11.9756 12.6004 11.9205 12.554 11.874Z" fill="#EBEBEB" stroke="#EBEBEB" stroke-width="0.4"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-add-note-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-add-note-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<form id="omnivore-add-note-form">
|
||||||
|
<textarea id="omnivore-add-note-textarea" name="title"></textarea>
|
||||||
|
<button class="omnivore-save-button">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="omnivore-edit-title-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-edit-title-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<form id="omnivore-edit-title-form">
|
||||||
|
<textarea id="omnivore-edit-title-textarea" name="title"></textarea>
|
||||||
|
<button class="omnivore-save-button">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="omnivore-edit-labels-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<form id="omnivore-edit-labels-form">
|
||||||
|
<span id="omnivore-edit-labels-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<div id="omnivore-edit-labels-list"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-extra-buttons-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-extra-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<button id="omnivore-toast-edit-title-btn">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.5625 4.50004L13.5 8.43754M6.71406 15.1516L2.84828 11.2858M6.517 15.1875H3.375C3.22582 15.1875 3.08274 15.1283 2.97725 15.0228C2.87176 14.9173 2.8125 14.7742 2.8125 14.625V11.483C2.8125 11.4092 2.82705 11.336 2.85532 11.2678C2.88359 11.1995 2.92502 11.1375 2.97725 11.0853L11.4148 2.64778C11.5202 2.5423 11.6633 2.48303 11.8125 2.48303C11.9617 2.48303 12.1048 2.5423 12.2102 2.64778L15.3523 5.78979C15.4577 5.89528 15.517 6.03835 15.517 6.18754C15.517 6.33672 15.4577 6.4798 15.3523 6.58528L6.91475 15.0228C6.86252 15.075 6.80051 15.1165 6.73226 15.1447C6.66402 15.173 6.59087 15.1875 6.517 15.1875Z" stroke="#6A6968" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
Edit Title
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-menu-divider"></span>
|
||||||
|
<button id="omnivore-toast-archive-btn">
|
||||||
|
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16.0143 0.166748H1.93155C1.157 0.166748 0.523193 0.800512 0.523193 1.5751V3.92222C0.523193 4.6264 1.03956 5.18958 1.69675 5.30698V14.0148C1.69675 14.7893 2.33052 15.4231 3.10511 15.4231H14.8407C15.6152 15.4231 16.249 14.7894 16.249 14.0148V5.30698C16.9062 5.18959 17.4226 4.6264 17.4226 3.92222V1.5751C17.4226 0.800554 16.7888 0.166748 16.0143 0.166748ZM1.93155 1.5751H16.0143V3.92222H1.93155V1.5751ZM14.8407 14.0148H3.10511V5.33049H14.8407V14.0148Z" fill="#6A6968"/>
|
||||||
|
<path d="M7.82307 8.26431H10.1702C10.5692 8.26431 10.8744 7.95914 10.8744 7.56013C10.8744 7.16114 10.5692 6.85596 10.1702 6.85596H7.82307C7.42408 6.85596 7.1189 7.16113 7.1189 7.56013C7.1189 7.95912 7.44748 8.26431 7.82307 8.26431Z" fill="#6A6968"/>
|
||||||
|
</svg>
|
||||||
|
Archive
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-menu-divider"></span>
|
||||||
|
<button id="omnivore-toast-delete-btn">
|
||||||
|
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16.6602 5.16992L3.51147 5.16993" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8.29272 8.91992V13.9199" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11.8787 8.91992V13.9199" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.09741 2.66992H13.0741" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.4648 5.16993V17.0449C15.4648 17.2107 15.4018 17.3697 15.2897 17.4869C15.1777 17.6041 15.0256 17.6699 14.8671 17.6699H5.30445C5.14594 17.6699 4.99392 17.6041 4.88184 17.4869C4.76976 17.3697 4.70679 17.2107 4.70679 17.0449V5.16992" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-logged-out-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-logged-out-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<a href="" id="omnivore-toast-login-btn">Login to Omnivore</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
BIN
pkg/extension-v3/firefox-3.0-src.zip
Normal file
BIN
pkg/extension-v3/firefox-3.0.zip
Normal file
25
pkg/extension-v3/package.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "omnivore-extension",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "browser extension for omnivore",
|
||||||
|
"scripts": {
|
||||||
|
"build": "env webpack --mode production",
|
||||||
|
"watch": "webpack --mode development --watch"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/chrome": "^0.0.268",
|
||||||
|
"@types/dompurify": "^3.0.5",
|
||||||
|
"@types/firefox-webext-browser": "^120.0.4",
|
||||||
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
|
"copy-webpack-plugin": "^12.0.2",
|
||||||
|
"dotenv-webpack": "^8.1.0",
|
||||||
|
"ts-loader": "^8.0.0",
|
||||||
|
"typescript": "^4.0.0",
|
||||||
|
"webpack": "^5.0.0",
|
||||||
|
"webpack-cli": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^4.0.2",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
90
pkg/extension-v3/src/background.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { addNoteToLibraryItem, savePageRequest } from './scripts/omnivore-api'
|
||||||
|
import {
|
||||||
|
isAddNoteInput,
|
||||||
|
isEnqueueTaskMessage,
|
||||||
|
isSavePageInput,
|
||||||
|
} from './scripts/types'
|
||||||
|
import { TaskQueue } from './task-queue'
|
||||||
|
|
||||||
|
const browserAPI = typeof browser !== 'undefined' ? browser : chrome
|
||||||
|
|
||||||
|
const taskQueues: Record<string, TaskQueue> = {}
|
||||||
|
|
||||||
|
chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
|
||||||
|
console.log('message: ', message, 'sender', sender.tab?.id)
|
||||||
|
|
||||||
|
const tabId = sender.tab?.id
|
||||||
|
if (message.action === 'savePage' && isSavePageInput(message)) {
|
||||||
|
const { result, libraryItemId } = await savePageRequest({
|
||||||
|
url: message.url,
|
||||||
|
title: message.title,
|
||||||
|
clientRequestId: message.clientRequestId,
|
||||||
|
originalContent: message.originalContent,
|
||||||
|
})
|
||||||
|
console.log('result: ', result, 'libraryItemId', libraryItemId)
|
||||||
|
if (tabId) {
|
||||||
|
switch (result) {
|
||||||
|
case 'success':
|
||||||
|
chrome.tabs.sendMessage(tabId, {
|
||||||
|
message: 'startToolbarDismiss',
|
||||||
|
status: 'success',
|
||||||
|
})
|
||||||
|
if (libraryItemId) {
|
||||||
|
const taskQueue = taskQueues[message.clientRequestId]
|
||||||
|
taskQueue.setReady(tabId, libraryItemId)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'failure':
|
||||||
|
chrome.tabs.sendMessage(tabId, {
|
||||||
|
message: 'startToolbarDismiss',
|
||||||
|
status: 'failure',
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 'unauthorized':
|
||||||
|
chrome.tabs.sendMessage(tabId, {
|
||||||
|
message: 'showLoggedOutToolbar',
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (message.action == 'enqueueTask' && isEnqueueTaskMessage(message)) {
|
||||||
|
const taskQueue = taskQueues[message.clientRequestId]
|
||||||
|
console.log('enqueing task message: ', message)
|
||||||
|
taskQueue.enqueue({ ...message, libraryItemId: message.clientRequestId })
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
const scriptsAlreadyLoaded = async (tabId: number) => {
|
||||||
|
try {
|
||||||
|
const pingCheck = await chrome.tabs.sendMessage(tabId, {
|
||||||
|
message: 'ping',
|
||||||
|
})
|
||||||
|
console.log('pingCheck: ', pingCheck)
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
browserAPI.action.onClicked.addListener(async (tab) => {
|
||||||
|
const tabId = tab.id
|
||||||
|
if (tabId) {
|
||||||
|
try {
|
||||||
|
const scriptsLoaded = await scriptsAlreadyLoaded(tabId)
|
||||||
|
if (!scriptsLoaded) {
|
||||||
|
await chrome.scripting.executeScript({
|
||||||
|
target: { tabId },
|
||||||
|
files: ['content.js'],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[omnivore] error injecting content script: ', err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const clientRequestId = uuidv4()
|
||||||
|
taskQueues[clientRequestId] = new TaskQueue()
|
||||||
|
chrome.tabs.sendMessage(tabId, { message: 'savePage', clientRequestId })
|
||||||
|
}
|
||||||
|
})
|
||||||
BIN
pkg/extension-v3/src/icons/icon-128.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
pkg/extension-v3/src/icons/icon-16.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
pkg/extension-v3/src/icons/icon-19.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
pkg/extension-v3/src/icons/icon-24.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
pkg/extension-v3/src/icons/icon-256.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
pkg/extension-v3/src/icons/icon-32.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
pkg/extension-v3/src/icons/icon-38.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
pkg/extension-v3/src/icons/icon-48.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
pkg/extension-v3/src/icons/icon-70.png
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
pkg/extension-v3/src/icons/icon-96.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
14
pkg/extension-v3/src/images/highlight.svg
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4278)">
|
||||||
|
<path d="M8 20.8342H11.3333L20.0833 12.0842C20.5254 11.6422 20.7737 11.0427 20.7737 10.4176C20.7737 9.79245 20.5254 9.19293 20.0833 8.7509C19.6413 8.30888 19.0418 8.06055 18.4167 8.06055C17.7915 8.06055 17.192 8.30888 16.75 8.7509L8 17.5009V20.8342Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.9166 9.58398L19.25 12.9173" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M9.25 16.25L12.5833 19.5833" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M23 17.5V20.8333H16.3334L19.6667 17.5H23Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4278">
|
||||||
|
<rect width="20" height="20" fill="white" transform="translate(5.5 5)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
12
pkg/extension-v3/src/images/label.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4271)">
|
||||||
|
<path d="M10.9166 12.2493C10.9166 12.4704 11.0044 12.6823 11.1607 12.8386C11.317 12.9949 11.5289 13.0827 11.75 13.0827C11.971 13.0827 12.1829 12.9949 12.3392 12.8386C12.4955 12.6823 12.5833 12.4704 12.5833 12.2493C12.5833 12.0283 12.4955 11.8164 12.3392 11.6601C12.1829 11.5038 11.971 11.416 11.75 11.416C11.5289 11.416 11.317 11.5038 11.1607 11.6601C11.0044 11.8164 10.9166 12.0283 10.9166 12.2493Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8 11V15.31C8.00009 15.752 8.17575 16.1758 8.48833 16.4883L14.9133 22.9133C15.29 23.2899 15.8007 23.5015 16.3333 23.5015C16.8659 23.5015 17.3767 23.2899 17.7533 22.9133L22.4133 18.2533C22.7899 17.8767 23.0015 17.3659 23.0015 16.8333C23.0015 16.3007 22.7899 15.79 22.4133 15.4133L15.9883 8.98833C15.6758 8.67575 15.252 8.50009 14.81 8.5H10.5C9.83696 8.5 9.20107 8.76339 8.73223 9.23223C8.26339 9.70107 8 10.337 8 11Z" stroke="white" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4271">
|
||||||
|
<rect width="20" height="20" fill="white" transform="translate(5.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
11
pkg/extension-v3/src/images/listen-hover.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle class="circle-bg" cx="15.5" cy="15" r="15" fill="#6A6968"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4264)">
|
||||||
|
<path d="M11 9.00021V21.0002C11 21.1337 11.0355 21.2647 11.103 21.3798C11.1705 21.4949 11.2675 21.5899 11.384 21.6551C11.5005 21.7202 11.6322 21.753 11.7657 21.7503C11.8991 21.7475 12.0293 21.7091 12.143 21.6392L21.893 15.6392C22.0022 15.5721 22.0924 15.4781 22.1549 15.3663C22.2175 15.2544 22.2503 15.1284 22.2503 15.0002C22.2503 14.872 22.2175 14.746 22.1549 14.6341C22.0924 14.5223 22.0022 14.4283 21.893 14.3612L12.143 8.36121C12.0293 8.29128 11.8991 8.25295 11.7657 8.25016C11.6322 8.24738 11.5005 8.28024 11.384 8.34536C11.2675 8.41048 11.1705 8.50549 11.103 8.62061C11.0355 8.73572 11 8.86676 11 9.00021Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4264">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 976 B |
11
pkg/extension-v3/src/images/listen.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle class="circle-bg" cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4264)">
|
||||||
|
<path d="M11 9.00021V21.0002C11 21.1337 11.0355 21.2647 11.103 21.3798C11.1705 21.4949 11.2675 21.5899 11.384 21.6551C11.5005 21.7202 11.6322 21.753 11.7657 21.7503C11.8991 21.7475 12.0293 21.7091 12.143 21.6392L21.893 15.6392C22.0022 15.5721 22.0924 15.4781 22.1549 15.3663C22.2175 15.2544 22.2503 15.1284 22.2503 15.0002C22.2503 14.872 22.2175 14.746 22.1549 14.6341C22.0924 14.5223 22.0022 14.4283 21.893 14.3612L12.143 8.36121C12.0293 8.29128 11.8991 8.25295 11.7657 8.25016C11.6322 8.24738 11.5005 8.28024 11.384 8.34536C11.2675 8.41048 11.1705 8.50549 11.103 8.62061C11.0355 8.73572 11 8.86676 11 9.00021Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4264">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 976 B |
3
pkg/extension-v3/src/images/pause-w-circle.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M15.5076 30.1582C23.7381 30.1582 30.5 23.3963 30.5 15.1659C30.5 6.92006 23.7381 0.158203 15.4924 0.158203C7.26186 0.158203 0.5 6.92006 0.5 15.1659C0.5 23.3963 7.26186 30.1582 15.5076 30.1582ZM15.5076 28.9955C7.85849 28.9955 1.66267 22.7997 1.66267 15.1659C1.66267 7.53199 7.85849 1.32088 15.4924 1.32088C23.1415 1.32088 29.3373 7.53199 29.3373 15.1659C29.3373 22.7997 23.1415 28.9955 15.5076 28.9955ZM11.3465 20.918H12.9069C13.5342 20.918 13.8248 20.5662 13.8248 20.0613V10.2398C13.8248 9.73495 13.5342 9.38309 12.9069 9.38309H11.3465C10.7346 9.38309 10.4286 9.73495 10.4286 10.2398V20.0613C10.4286 20.5662 10.7346 20.918 11.3465 20.918ZM18.0931 20.918H19.6382C20.2501 20.918 20.5561 20.5662 20.5561 20.0613V10.2398C20.5561 9.73495 20.2501 9.38309 19.6382 9.38309H18.0931C17.4658 9.38309 17.1752 9.73495 17.1752 10.2398V20.0613C17.1752 20.5662 17.4658 20.918 18.0931 20.918Z" fill="#D9D9D9"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1005 B |
5
pkg/extension-v3/src/images/playback-speed.svg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<svg width="31" height="32" viewBox="0 0 31 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="16.1582" r="15" fill="#3D3D3D"/>
|
||||||
|
<path d="M15.5 31.1582C13.5302 31.1582 11.5796 30.7702 9.75975 30.0164C7.93986 29.2626 6.28628 28.1577 4.8934 26.7648C3.50052 25.3719 2.39563 23.7183 1.64181 21.8985C0.887985 20.0786 0.499999 18.128 0.499999 16.1582C0.5 14.1884 0.887986 12.2378 1.64181 10.4179C2.39563 8.59807 3.50052 6.94448 4.8934 5.5516C6.28628 4.15872 7.93987 3.05383 9.75975 2.30001C11.5796 1.54619 13.5302 1.1582 15.5 1.1582C17.4698 1.1582 19.4204 1.54619 21.2403 2.30001C23.0601 3.05383 24.7137 4.15872 26.1066 5.5516C27.4995 6.94448 28.6044 8.59807 29.3582 10.418C30.112 12.2378 30.5 14.1884 30.5 16.1582C30.5 18.128 30.112 20.0786 29.3582 21.8985C28.6044 23.7183 27.4995 25.3719 26.1066 26.7648C24.7137 28.1577 23.0601 29.2626 21.2402 30.0164C19.4204 30.7702 17.4698 31.1582 15.5 31.1582L15.5 31.1582Z" stroke="#898989"/>
|
||||||
|
<path d="M8.26074 20.1582V14.4648H8.23145L6.43457 15.7051V14.377L8.25586 13.1123H9.7207V20.1582H8.26074ZM12.0693 20.2168C11.6299 20.2168 11.2832 19.8652 11.2832 19.4307C11.2832 18.9912 11.6299 18.6445 12.0693 18.6445C12.5039 18.6445 12.8555 18.9912 12.8555 19.4307C12.8555 19.8652 12.5039 20.2168 12.0693 20.2168ZM16.6299 20.3145C15.1162 20.3145 14.0273 19.416 13.9834 18.1416H15.3457C15.4287 18.7373 15.9561 19.1475 16.6396 19.1475C17.4111 19.1475 17.9434 18.6104 17.9434 17.8438C17.9434 17.0625 17.4111 16.5156 16.6494 16.5156C16.1172 16.5156 15.6582 16.7598 15.4141 17.165H14.0957L14.4424 13.1123H18.9248V14.2842H15.5996L15.4385 16.2129H15.4678C15.7559 15.7393 16.3174 15.4414 17.0352 15.4414C18.3828 15.4414 19.3496 16.4326 19.3496 17.8047C19.3496 19.2988 18.2461 20.3145 16.6299 20.3145ZM22.2402 18.3418H22.2109L21.2295 20.1582H19.7305L21.3711 17.5508L19.7402 14.9238H21.3467L22.2891 16.6914H22.3184L23.2461 14.9238H24.7988L23.1631 17.5117L24.7842 20.1582H23.2363L22.2402 18.3418Z" fill="white"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
15
pkg/extension-v3/src/images/playback-voice.svg
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<svg width="31" height="32" viewBox="0 0 31 32" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="16.1582" r="15" fill="#3D3D3D"/>
|
||||||
|
<path d="M15.5 31.1582C13.5302 31.1582 11.5796 30.7702 9.75975 30.0164C7.93986 29.2626 6.28628 28.1577 4.8934 26.7648C3.50052 25.3719 2.39563 23.7183 1.64181 21.8985C0.887985 20.0786 0.499999 18.128 0.499999 16.1582C0.5 14.1884 0.887986 12.2378 1.64181 10.4179C2.39563 8.59807 3.50052 6.94448 4.8934 5.5516C6.28628 4.15872 7.93987 3.05383 9.75975 2.30001C11.5796 1.54619 13.5302 1.1582 15.5 1.1582C17.4698 1.1582 19.4204 1.54619 21.2403 2.30001C23.0601 3.05383 24.7137 4.15872 26.1066 5.5516C27.4995 6.94448 28.6044 8.59807 29.3582 10.418C30.112 12.2378 30.5 14.1884 30.5 16.1582C30.5 18.128 30.112 20.0786 29.3582 21.8985C28.6044 23.7183 27.4995 25.3719 26.1066 26.7648C24.7137 28.1577 23.0601 29.2626 21.2402 30.0164C19.4204 30.7702 17.4698 31.1582 15.5 31.1582L15.5 31.1582Z" stroke="#898989"/>
|
||||||
|
<g clip-path="url(#clip0_11902_5015)">
|
||||||
|
<path d="M18.1266 11.6096C17.9021 11.8338 17.902 12.1975 18.1263 12.4219C19.6353 13.932 19.6344 16.39 18.1241 17.9011C17.8999 18.1256 17.9 18.4892 18.1243 18.7135C18.2366 18.8256 18.3835 18.8817 18.5305 18.8817C18.6776 18.8817 18.8247 18.8255 18.9369 18.7133C20.8945 16.7543 20.8955 13.5678 18.939 11.6098C18.7148 11.3854 18.351 11.3852 18.1266 11.6096Z" fill="white"/>
|
||||||
|
<path d="M15.979 13.2581C15.7545 13.4822 15.7544 13.846 15.9787 14.0704C16.5803 14.6725 16.5802 15.6521 15.9786 16.2541C15.7543 16.4785 15.7544 16.8422 15.9789 17.0665C16.091 17.1786 16.238 17.2346 16.3849 17.2346C16.532 17.2346 16.6791 17.1785 16.7913 17.0662C17.8404 16.0164 17.8404 14.3081 16.7914 13.2583C16.5672 13.0338 16.2034 13.0337 15.979 13.2581Z" fill="white"/>
|
||||||
|
<path d="M21.4821 9.06494C21.2578 8.84045 20.8941 8.84033 20.6697 9.0646C20.4452 9.28886 20.4451 9.65261 20.6694 9.87699C23.5803 12.7897 23.579 17.5303 20.6665 20.4444C20.4421 20.6687 20.4423 21.0325 20.6667 21.2567C20.7789 21.3688 20.9258 21.4249 21.0728 21.4249C21.2198 21.4249 21.367 21.3687 21.4791 21.2565C24.8392 17.8946 24.8405 12.4254 21.4821 9.06494Z" fill="white"/>
|
||||||
|
<path d="M11.1793 18.8664C12.6562 18.7646 13.8271 17.5299 13.8271 16.0258C13.8271 14.4553 12.5508 13.1777 10.9821 13.1777C9.4133 13.1777 8.13699 14.4553 8.13699 16.0258C8.13699 17.5298 9.30775 18.7645 10.7848 18.8664C9.67895 18.9089 8.70503 19.3084 8.02629 20.0031C7.32894 20.7169 6.97457 21.705 7.00142 22.861C7.00869 23.1729 7.26363 23.4221 7.5757 23.4221H14.3878C14.6999 23.4221 14.9549 23.1729 14.9621 22.8609C14.989 21.7049 14.6345 20.7166 13.9371 20.0029C13.2585 19.3083 12.2849 18.9089 11.1793 18.8664ZM9.28589 16.0258C9.28589 15.0889 10.0468 14.3266 10.9821 14.3266C11.9173 14.3266 12.6782 15.0889 12.6782 16.0258C12.6782 16.9628 11.9173 17.7251 10.9821 17.7251C10.0468 17.7251 9.28589 16.9628 9.28589 16.0258ZM8.17677 22.2731C8.25158 21.6784 8.4763 21.1866 8.84812 20.8061C9.34897 20.2935 10.1068 20.0112 10.9819 20.0112C11.857 20.0112 12.6146 20.2934 13.1154 20.8059C13.4871 21.1863 13.712 21.6783 13.7867 22.2731H8.17677Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11902_5015">
|
||||||
|
<rect width="17" height="17" fill="white" transform="translate(7 7.6582)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.1 KiB |
11
pkg/extension-v3/src/images/save.svg
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<svg width="31" height="30" viewBox="0 0 31 30" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="15.5" cy="15" r="15" fill="#3D3D3D"/>
|
||||||
|
<g clip-path="url(#clip0_11897_4287)">
|
||||||
|
<path d="M17 7.5C17.9946 7.5 18.9484 7.89509 19.6517 8.59835C20.3549 9.30161 20.75 10.2554 20.75 11.25V21.75C20.75 21.8858 20.7132 22.019 20.6434 22.1355C20.5736 22.252 20.4735 22.3473 20.3538 22.4114C20.2341 22.4755 20.0992 22.5058 19.9636 22.4992C19.828 22.4926 19.6967 22.4494 19.5837 22.374L15.5 19.6515L11.417 22.374C11.31 22.4456 11.1863 22.4885 11.0579 22.4985C10.9295 22.5084 10.8007 22.4852 10.6839 22.4309C10.5671 22.3766 10.4662 22.2932 10.391 22.1887C10.3158 22.0841 10.2688 21.962 10.2545 21.834L10.25 21.75V11.25C10.25 10.2554 10.6451 9.30161 11.3483 8.59835C12.0516 7.89509 13.0054 7.5 14 7.5H17Z" fill="white"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_11897_4287">
|
||||||
|
<rect width="18" height="18" fill="white" transform="translate(6.5 6)"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 958 B |
42
pkg/extension-v3/src/manifest.json
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "Omnivore - Self Hosted",
|
||||||
|
"version": "3.0",
|
||||||
|
"description": "Save content to your Omnivore library.",
|
||||||
|
"permissions": [
|
||||||
|
"activeTab",
|
||||||
|
"scripting",
|
||||||
|
"storage"
|
||||||
|
],
|
||||||
|
"host_permissions": [
|
||||||
|
"<all_urls>"
|
||||||
|
],
|
||||||
|
"background": {
|
||||||
|
"service_worker": "background.js",
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"web_accessible_resources": [
|
||||||
|
{
|
||||||
|
"resources": [
|
||||||
|
"images/*.svg",
|
||||||
|
"views/toast.html"
|
||||||
|
],
|
||||||
|
"matches": [
|
||||||
|
"<all_urls>"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"options_page": "views/options.html",
|
||||||
|
"action": {
|
||||||
|
"default_icon": {
|
||||||
|
"16": "icons/icon-16.png",
|
||||||
|
"48": "icons/icon-48.png",
|
||||||
|
"128": "icons/icon-128.png"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"icons": {
|
||||||
|
"16": "icons/icon-16.png",
|
||||||
|
"48": "icons/icon-48.png",
|
||||||
|
"128": "icons/icon-128.png"
|
||||||
|
}
|
||||||
|
}
|
||||||
87
pkg/extension-v3/src/scripts/content/content.ts
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import { SavePageInput, ToolbarMessage } from '../types'
|
||||||
|
import {
|
||||||
|
showLoggedOutToolbar,
|
||||||
|
showToolbar,
|
||||||
|
startToolbarDismiss,
|
||||||
|
updateToolbarStatus
|
||||||
|
} from './toolbar'
|
||||||
|
import { editLabels } from './labels'
|
||||||
|
|
||||||
|
const collectPageContent = async (): Promise<string> => {
|
||||||
|
const mainContent = document.documentElement.outerHTML
|
||||||
|
console.log('[omnivore] captured mainContent')
|
||||||
|
return mainContent
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleToolbarMessage = async (
|
||||||
|
request: any,
|
||||||
|
sender: chrome.runtime.MessageSender,
|
||||||
|
sendResponse: (response?: any) => void
|
||||||
|
) => {
|
||||||
|
console.log('[omnivore] content script message:', request)
|
||||||
|
|
||||||
|
switch (request.message) {
|
||||||
|
case 'showLoggedOutToolbar':
|
||||||
|
showLoggedOutToolbar()
|
||||||
|
sendResponse({ success: true })
|
||||||
|
break
|
||||||
|
case 'updateToolbar':
|
||||||
|
updateToolbarStatus(request.status, request.task)
|
||||||
|
|
||||||
|
sendResponse({ success: true })
|
||||||
|
break
|
||||||
|
case 'startToolbarDismiss':
|
||||||
|
startToolbarDismiss(request as ToolbarMessage)
|
||||||
|
sendResponse({ success: true })
|
||||||
|
return
|
||||||
|
case 'updateLabelCache':
|
||||||
|
editLabels()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
sendResponse({ success: false })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setupToolbar = async (clientRequestId: string) => {
|
||||||
|
// toolbar message listener
|
||||||
|
if (!chrome.runtime.onMessage.hasListener(handleToolbarMessage)) {
|
||||||
|
chrome.runtime.onMessage.addListener(handleToolbarMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
await showToolbar(clientRequestId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const savePage = async (clientRequestId: string) => {
|
||||||
|
console.log('[omnivore] v3 extension triggered: ', clientRequestId)
|
||||||
|
|
||||||
|
await setupToolbar(clientRequestId)
|
||||||
|
|
||||||
|
const content = await collectPageContent()
|
||||||
|
console.log('[omnivore] collected page content: ', content)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const page: SavePageInput = {
|
||||||
|
clientRequestId,
|
||||||
|
title: document.title,
|
||||||
|
url: document.location.href,
|
||||||
|
originalContent: content,
|
||||||
|
}
|
||||||
|
await chrome.runtime.sendMessage({
|
||||||
|
action: 'savePage',
|
||||||
|
...page,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error sending content: ', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// toolbar message listener
|
||||||
|
chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
|
||||||
|
switch (request.message) {
|
||||||
|
case 'savePage':
|
||||||
|
await savePage(request.clientRequestId)
|
||||||
|
sendResponse({ success: true })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
177
pkg/extension-v3/src/scripts/content/labels.ts
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
import { getStorageItem } from '../utils'
|
||||||
|
import { Label } from '../types'
|
||||||
|
import { cancelAutoDismiss, getClientRequestId, toggleRow, updateStatusBox, updateToolbarStatus } from './toolbar'
|
||||||
|
|
||||||
|
export async function editLabels() {
|
||||||
|
cancelAutoDismiss()
|
||||||
|
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
|
||||||
|
if (!currentToastEl || !currentToastEl.shadowRoot) {
|
||||||
|
console.log('no statusBox to update')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let labels = await getStorageItem('labels').then((value: any) => {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
return value as Label[]
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
toggleRow('#omnivore-edit-labels-row')
|
||||||
|
currentToastEl.shadowRoot
|
||||||
|
.querySelector<HTMLInputElement>('#omnivore-edit-label-input')
|
||||||
|
?.focus()
|
||||||
|
|
||||||
|
const list = currentToastEl.shadowRoot.querySelector(
|
||||||
|
'#omnivore-edit-labels-list'
|
||||||
|
)
|
||||||
|
|
||||||
|
// Add a box for waiting for the labels.
|
||||||
|
if (!labels) {
|
||||||
|
console.error('No labels found, trying to update the cache.')
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'updateLabelCache',
|
||||||
|
clientRequestId: getClientRequestId(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// currentToastEl.shadowRoot.querySelector(
|
||||||
|
// '#omnivore-edit-label-input'
|
||||||
|
// )<HTMLInputElement>.onkeydown = labelEditorKeyDownHandler
|
||||||
|
//
|
||||||
|
// currentToastEl.shadowRoot.querySelector(
|
||||||
|
// '#omnivore-edit-label-editor'
|
||||||
|
// )<HTMLInputElement>.onclick = labelEditorClickHandler
|
||||||
|
//
|
||||||
|
// currentToastEl.shadowRoot
|
||||||
|
// .querySelector<HTMLInputElement>('#omnivore-edit-label-input')
|
||||||
|
// .addEventListener('input', (event) => {
|
||||||
|
// updateLabels(event.target.value)
|
||||||
|
// })
|
||||||
|
|
||||||
|
if (list) {
|
||||||
|
list.innerHTML = ''
|
||||||
|
labels
|
||||||
|
.sort((a, b) =>
|
||||||
|
a.name.localeCompare(b.name, undefined, { sensitivity: 'base' })
|
||||||
|
)
|
||||||
|
.forEach(function (label, idx) {
|
||||||
|
const rowHtml = createLabelRow(label)
|
||||||
|
list.appendChild(rowHtml)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLabelRow(label: Label) {
|
||||||
|
const element = document.createElement('button')
|
||||||
|
const dot = document.createElement('span')
|
||||||
|
// @ts-ignore
|
||||||
|
dot.style = 'width:10px;height:10px;border-radius:1000px;'
|
||||||
|
dot.style.setProperty('background-color', label.color)
|
||||||
|
const title = document.createElement('span')
|
||||||
|
// @ts-ignore
|
||||||
|
title.style = 'margin-left: 10px;pointer-events: none;'
|
||||||
|
title.innerText = label.name
|
||||||
|
|
||||||
|
const check = document.createElement('span')
|
||||||
|
// @ts-ignore
|
||||||
|
check.style = 'margin-left: auto;pointer-events: none;'
|
||||||
|
check.className = 'checkbox'
|
||||||
|
check.innerHTML = `
|
||||||
|
<svg width="14" height="11" viewBox="0 0 14 11" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13.7411 1.75864L4.79692 10.7028L0.69751 6.60341L1.74845 5.55246L4.79692 8.59348L12.6902 0.707703L13.7411 1.75864Z" fill="#888888"/>
|
||||||
|
</svg>
|
||||||
|
`
|
||||||
|
|
||||||
|
element.appendChild(dot)
|
||||||
|
element.appendChild(title)
|
||||||
|
element.appendChild(check)
|
||||||
|
|
||||||
|
element.onclick = labelClick
|
||||||
|
// element.onkeydown = labelEditorKeyDownHandler
|
||||||
|
element.setAttribute('data-label-id', label.id)
|
||||||
|
element.setAttribute(
|
||||||
|
'data-label-selected',
|
||||||
|
label['selected'] ? 'on' : 'off'
|
||||||
|
)
|
||||||
|
element.setAttribute('tabIndex', '-1')
|
||||||
|
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function labelClick(event: any) {
|
||||||
|
event.preventDefault()
|
||||||
|
const labelId = event.target?.getAttribute('data-label-id')
|
||||||
|
|
||||||
|
if (labelId) {
|
||||||
|
toggleLabel(event, labelId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function toggleLabel(event: any, labelId: string) {
|
||||||
|
const labelSelected = event.target?.getAttribute('data-label-selected')
|
||||||
|
|
||||||
|
if (!labelId || !labelSelected) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggledValue = labelSelected == 'on' ? false : true
|
||||||
|
event.target?.setAttribute(
|
||||||
|
'data-label-selected',
|
||||||
|
toggledValue ? 'on' : 'off'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
let labels = await getStorageItem('labels').then((value: any) => {
|
||||||
|
if (value && value.length > 0) {
|
||||||
|
return value as Label[]
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!labels) {
|
||||||
|
throw Error("No labels selected")
|
||||||
|
}
|
||||||
|
|
||||||
|
const label = labels.find((l) => l.id === labelId)
|
||||||
|
if (label) {
|
||||||
|
syncLabelChanges()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncLabelChanges() {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-edit-labels-status',
|
||||||
|
'waiting',
|
||||||
|
'Updating Labels...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const labels = currentToastEl?.shadowRoot?.querySelector("#omnivore-edit-labels-list")
|
||||||
|
|
||||||
|
if (labels) {
|
||||||
|
const setLabels = [...labels.children]
|
||||||
|
.filter((l) => l.getAttribute('data-label-selected') === 'on')
|
||||||
|
.map((l) => l.getAttribute('data-label-id')!)
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'setLabels',
|
||||||
|
clientRequestId: getClientRequestId(),
|
||||||
|
labels: setLabels,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
593
pkg/extension-v3/src/scripts/content/toolbar.ts
Normal file
@ -0,0 +1,593 @@
|
|||||||
|
import { ToolbarMessage, ToolbarStatus } from '../types'
|
||||||
|
import { getStorageItem, setStorage } from '../utils'
|
||||||
|
import { editLabels } from './labels'
|
||||||
|
|
||||||
|
const systemIcons: { [key: string]: string } = {
|
||||||
|
waiting: '<div class="loading-spinner"></div>',
|
||||||
|
success: `
|
||||||
|
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.91626 18.6047C14.8868 18.6047 18.9163 14.5752 18.9163 9.60468C18.9163 4.63411 14.8868 0.604675 9.91626 0.604675C4.9457 0.604675 0.91626 4.63411 0.91626 9.60468C0.91626 14.5752 4.9457 18.6047 9.91626 18.6047ZM9.91626 17.1046C14.0584 17.1046 17.4163 13.7468 17.4163 9.60463C17.4163 5.4625 14.0584 2.10463 9.91626 2.10463C5.77412 2.10463 2.41626 5.4625 2.41626 9.60463C2.41626 13.7468 5.77412 17.1046 9.91626 17.1046Z" fill="#32D74B"/>
|
||||||
|
<path d="M13.3538 7.28851L8.7704 11.9209L6.47876 9.60469" stroke="#32D74B" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>`,
|
||||||
|
failure: `
|
||||||
|
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.74048 18.5508C14.711 18.5508 18.7405 14.5213 18.7405 9.55078C18.7405 4.58022 14.711 0.550781 9.74048 0.550781C4.76992 0.550781 0.740479 4.58022 0.740479 9.55078C0.740479 14.5213 4.76992 18.5508 9.74048 18.5508ZM9.74048 17.0507C13.8826 17.0507 17.2405 13.6929 17.2405 9.55074C17.2405 5.4086 13.8826 2.05074 9.74048 2.05074C5.59834 2.05074 2.24048 5.4086 2.24048 9.55074C2.24048 13.6929 5.59834 17.0507 9.74048 17.0507Z" fill="#C7372F"/>
|
||||||
|
<path d="M12.794 11.897L12.794 11.897L10.4474 9.55078L12.794 7.2046L12.794 7.20459C12.8878 7.11079 12.9405 6.98358 12.9405 6.85093C12.9405 6.71828 12.8878 6.59107 12.794 6.49727C12.7002 6.40348 12.573 6.35078 12.4403 6.35078C12.3077 6.35078 12.1805 6.40348 12.0867 6.49727L12.0867 6.49728L9.74048 8.84382L7.3943 6.49728L7.39429 6.49727C7.30049 6.40348 7.17328 6.35078 7.04063 6.35078C6.90798 6.35078 6.78077 6.40348 6.68697 6.49727C6.59317 6.59107 6.54048 6.71828 6.54048 6.85093C6.54048 6.98358 6.59317 7.11079 6.68697 7.20459L6.68698 7.2046L9.03351 9.55078L6.68698 11.897L6.68697 11.897C6.59317 11.9908 6.54048 12.118 6.54048 12.2506C6.54048 12.3833 6.59317 12.5105 6.68697 12.6043C6.78077 12.6981 6.90798 12.7508 7.04063 12.7508C7.17328 12.7508 7.30049 12.6981 7.39429 12.6043L7.3943 12.6043L9.74048 10.2577L12.0867 12.6043L12.0867 12.6043C12.1331 12.6507 12.1882 12.6876 12.2489 12.7127C12.3096 12.7378 12.3746 12.7508 12.4403 12.7508C12.506 12.7508 12.571 12.7378 12.6317 12.7127C12.6924 12.6876 12.7474 12.6507 12.7938 12.6043C12.8878 12.5105 12.9405 12.3833 12.9405 12.2506C12.9405 12.118 12.8878 11.9908 12.7938 11.897L12.7939 11.897H12.794Z" fill="#C7372F" stroke="#C7372F" stroke-width="0.3"/>
|
||||||
|
</svg>
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const createToastContainer = async (clientRequestId: string) => {
|
||||||
|
console.log('===== CREATING TOAST CONTAINER ===== ')
|
||||||
|
const file = await fetch(chrome.runtime.getURL('views/toast.html'))
|
||||||
|
const html = await file.text()
|
||||||
|
|
||||||
|
const root = document.createElement('div')
|
||||||
|
root.tabIndex = 0
|
||||||
|
root.id = 'omnivore-extension-root'
|
||||||
|
root.attachShadow({ mode: 'open' })
|
||||||
|
root.style.opacity = '1.0'
|
||||||
|
|
||||||
|
if (root.shadowRoot) {
|
||||||
|
root.shadowRoot.innerHTML = `<style>:host {all initial;}</style>`
|
||||||
|
} else {
|
||||||
|
alert('Error opening Omnivore user interface.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const toastEl = document.createElement('div')
|
||||||
|
toastEl.id = '#omnivore-toast'
|
||||||
|
toastEl.innerHTML = html
|
||||||
|
toastEl.tabIndex = 0
|
||||||
|
root.shadowRoot.appendChild(toastEl)
|
||||||
|
|
||||||
|
document.body.appendChild(root)
|
||||||
|
connectButtons(root)
|
||||||
|
// connectKeyboard(root)
|
||||||
|
|
||||||
|
updateToolbarStatus('waiting')
|
||||||
|
|
||||||
|
return root
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showToolbar = async (clientRequestId: string) => {
|
||||||
|
let currentToastEl =
|
||||||
|
document.querySelector<HTMLElement>('#omnivore-extension-root') ?? undefined
|
||||||
|
|
||||||
|
const bodyEl = document.body
|
||||||
|
if (!bodyEl) return
|
||||||
|
|
||||||
|
console.log('existing currentToastEl: ', currentToastEl)
|
||||||
|
if (!currentToastEl) {
|
||||||
|
currentToastEl = await createToastContainer(clientRequestId)
|
||||||
|
}
|
||||||
|
|
||||||
|
const disableAutoDismiss = await getStorageItem('disableAutoDismiss')
|
||||||
|
if (disableAutoDismiss) {
|
||||||
|
currentToastEl?.setAttribute('data-disable-auto-dismiss', 'true')
|
||||||
|
}
|
||||||
|
currentToastEl?.setAttribute(
|
||||||
|
'data-omnivore-client-request-id',
|
||||||
|
clientRequestId
|
||||||
|
)
|
||||||
|
;(currentToastEl as HTMLDivElement)?.focus({
|
||||||
|
preventScroll: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
updateToolbarStatus('waiting')
|
||||||
|
}
|
||||||
|
|
||||||
|
const autoDismissTime = async () => {
|
||||||
|
const strVal = (await getStorageItem('autoDismissTime')) ?? '2500'
|
||||||
|
return !Number.isNaN(Number(strVal)) ? Number(strVal) : 2500
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateToolbarStatus = async (
|
||||||
|
status: ToolbarStatus,
|
||||||
|
task: string | undefined = undefined
|
||||||
|
) => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const statusBox = currentToastEl?.shadowRoot?.querySelector(
|
||||||
|
'.omnivore-toast-statusBox'
|
||||||
|
)
|
||||||
|
console.log('updating', status, statusBox)
|
||||||
|
|
||||||
|
if (statusBox) {
|
||||||
|
switch (status) {
|
||||||
|
case 'success':
|
||||||
|
statusBox.innerHTML = systemIcons.success
|
||||||
|
break
|
||||||
|
case 'failure':
|
||||||
|
statusBox.innerHTML = systemIcons.failure
|
||||||
|
break
|
||||||
|
case 'waiting':
|
||||||
|
statusBox.innerHTML = systemIcons.waiting
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a task specific message
|
||||||
|
if (task) {
|
||||||
|
if (task == 'addNote' && status == 'failure') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'failure',
|
||||||
|
'Error adding note...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (task == 'addNote' && status == 'success') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'success',
|
||||||
|
'Note updated.',
|
||||||
|
2500
|
||||||
|
)
|
||||||
|
setTimeout(() => {
|
||||||
|
toggleRow('#omnivore-add-note-status')
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
if (task == 'setLabels' && status == 'success') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-edit-labels-status',
|
||||||
|
'success',
|
||||||
|
'Labels Updated',
|
||||||
|
2500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (task == 'setLabels' && status == 'failure') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-edit-labels-status',
|
||||||
|
'failure',
|
||||||
|
'Error Updating Labels...',
|
||||||
|
2500
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (task == 'editTitle' && status == 'failure') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'failure',
|
||||||
|
'Error updating title...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (task == 'editTitle' && status == 'success') {
|
||||||
|
updateStatusBox(
|
||||||
|
'omnivore-edit-title-status',
|
||||||
|
'success',
|
||||||
|
'Title updated.',
|
||||||
|
2500
|
||||||
|
)
|
||||||
|
setTimeout(() => {
|
||||||
|
toggleRow('#omnivore-edit-title-status')
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
if (task == 'archive') {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-extra-status',
|
||||||
|
status,
|
||||||
|
status == 'success' ? 'Success' : 'Error',
|
||||||
|
status == 'success' ? 2500 : undefined
|
||||||
|
)
|
||||||
|
if (status == 'success') {
|
||||||
|
closeToolbarLater()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cancelAutoDismiss = () => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
if (currentToastEl) {
|
||||||
|
currentToastEl.setAttribute('data-disable-auto-dismiss', 'true')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user has not disabled auto dismiss on the toolbar this
|
||||||
|
// will remove it. If the user interacts with the toolbar, this
|
||||||
|
// dismiss will also be ignored.
|
||||||
|
export const startToolbarDismiss = async (message: ToolbarMessage) => {
|
||||||
|
if (message.status) {
|
||||||
|
updateToolbarStatus(message.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dimissTime = await autoDismissTime()
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
if (
|
||||||
|
currentToastEl &&
|
||||||
|
!currentToastEl.getAttribute('data-disable-auto-dismiss')
|
||||||
|
) {
|
||||||
|
;(currentToastEl as HTMLElement).style.transition = 'opacity 3.5s ease;'
|
||||||
|
;(currentToastEl as HTMLElement).style.opacity = '0'
|
||||||
|
setTimeout(() => {
|
||||||
|
const currentToastEl = document.querySelector(
|
||||||
|
'#omnivore-extension-root'
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
currentToastEl &&
|
||||||
|
!currentToastEl.getAttribute('data-disable-auto-dismiss')
|
||||||
|
) {
|
||||||
|
currentToastEl.remove()
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}, dimissTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
const connectButtons = (root: HTMLElement) => {
|
||||||
|
const btns = [
|
||||||
|
{ id: '#omnivore-toast-add-note-btn', func: addNote },
|
||||||
|
{ id: '#omnivore-toast-edit-title-btn', func: editTitle },
|
||||||
|
{ id: '#omnivore-toast-edit-labels-btn', func: editLabels },
|
||||||
|
{ id: '#omnivore-toast-read-now-btn', func: readNow },
|
||||||
|
{ id: '#omnivore-open-menu-btn', func: openMenu },
|
||||||
|
{ id: '#omnivore-toast-close-btn', func: closeToolbar },
|
||||||
|
{ id: '#omnivore-toast-login-btn', func: login },
|
||||||
|
{ id: '#omnivore-toast-archive-btn', func: archive },
|
||||||
|
{ id: '#omnivore-toast-delete-btn', func: deleteItem },
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const btnInfo of btns) {
|
||||||
|
const btn = root.shadowRoot?.querySelector(btnInfo.id)
|
||||||
|
if (btn) {
|
||||||
|
console.log(btnInfo.id)
|
||||||
|
btn.addEventListener('click', btnInfo.func)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = window.matchMedia('(max-width: 500px)')
|
||||||
|
if (x.matches) {
|
||||||
|
const labels = root.shadowRoot?.querySelectorAll<HTMLElement>(
|
||||||
|
'.omnivore-top-button-label'
|
||||||
|
)
|
||||||
|
labels?.forEach((label) => {
|
||||||
|
label.style.display = 'none'
|
||||||
|
})
|
||||||
|
const container = root.shadowRoot?.querySelector<HTMLElement>(
|
||||||
|
'#omnivore-toast-container'
|
||||||
|
)
|
||||||
|
if (container) {
|
||||||
|
container.style.width = '280px'
|
||||||
|
container.style.top = 'unset'
|
||||||
|
container.style.bottom = '20px'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function editTitle() {
|
||||||
|
cancelAutoDismiss()
|
||||||
|
toggleRow('#omnivore-edit-title-row')
|
||||||
|
let currentToastEl =
|
||||||
|
document.querySelector<HTMLElement>('#omnivore-extension-root') ?? undefined
|
||||||
|
|
||||||
|
if (!currentToastEl) {
|
||||||
|
console.log('no statusBox to update')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const titleArea = currentToastEl?.shadowRoot?.querySelector<HTMLTextAreaElement>(
|
||||||
|
'#omnivore-edit-title-textarea'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (titleArea) {
|
||||||
|
titleArea.focus()
|
||||||
|
|
||||||
|
titleArea.onkeydown = (e) => {
|
||||||
|
e.cancelBubble = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const formElement = currentToastEl?.shadowRoot?.querySelector<HTMLFormElement>(
|
||||||
|
'#omnivore-edit-title-form'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!formElement) {
|
||||||
|
console.log('no form to update')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
formElement.onsubmit = (event) => {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-edit-title-status',
|
||||||
|
'waiting',
|
||||||
|
'Updating title...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
const title = titleArea?.value ?? ''
|
||||||
|
|
||||||
|
chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'editTitle',
|
||||||
|
clientRequestId: getClientRequestId(),
|
||||||
|
title
|
||||||
|
})
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const showLoggedOutToolbar = () => {
|
||||||
|
cancelAutoDismiss()
|
||||||
|
updateToolbarStatus('failure')
|
||||||
|
toggleRow('#omnivore-logged-out-row')
|
||||||
|
disableAllButtons()
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-logged-out-status',
|
||||||
|
undefined,
|
||||||
|
`You are not logged in.`,
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateStatusBox = (
|
||||||
|
boxId: string,
|
||||||
|
state: ToolbarStatus | undefined,
|
||||||
|
message: string,
|
||||||
|
dismissAfter: number | undefined
|
||||||
|
) => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const statusBox = currentToastEl?.shadowRoot?.querySelector(boxId)
|
||||||
|
const image = (() => {
|
||||||
|
switch (state) {
|
||||||
|
case 'waiting':
|
||||||
|
return systemIcons.animatedLoader
|
||||||
|
case 'success':
|
||||||
|
return systemIcons.success
|
||||||
|
case 'failure':
|
||||||
|
return systemIcons.failure
|
||||||
|
default:
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
if (image && statusBox) {
|
||||||
|
const color = state == 'failure' ? 'red' : 'unset'
|
||||||
|
statusBox.innerHTML = `<span style='padding-right: 10px'>${image}</span><span style='line-height: 20px;color: ${color};text-decoration: none;'>${message}</span>`
|
||||||
|
} else if (statusBox) {
|
||||||
|
statusBox.innerHTML = message
|
||||||
|
}
|
||||||
|
if (dismissAfter && statusBox) {
|
||||||
|
setTimeout(() => {
|
||||||
|
statusBox.innerHTML = ''
|
||||||
|
}, dismissAfter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const disableAllButtons = () => {
|
||||||
|
const actionButtons = [
|
||||||
|
'#omnivore-toast-edit-title-btn',
|
||||||
|
'#omnivore-toast-edit-labels-btn',
|
||||||
|
'#omnivore-toast-read-now-btn',
|
||||||
|
'#omnivore-toast-add-note-btn',
|
||||||
|
'#omnivore-open-menu-btn',
|
||||||
|
]
|
||||||
|
let currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
actionButtons.forEach((btnId) => {
|
||||||
|
const btn =
|
||||||
|
currentToastEl?.shadowRoot?.querySelector<HTMLButtonElement>(btnId)
|
||||||
|
if (btn) {
|
||||||
|
btn.disabled = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toggleRow = (rowId: string) => {
|
||||||
|
let currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
|
||||||
|
if (!currentToastEl) {
|
||||||
|
console.log('toggleRow: no row to toggle')
|
||||||
|
// its possible this was called after closing the extension
|
||||||
|
// so just return
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const container = currentToastEl?.shadowRoot?.querySelector(rowId)
|
||||||
|
const initialState = container?.getAttribute('data-state')
|
||||||
|
const rows = currentToastEl?.shadowRoot?.querySelectorAll(
|
||||||
|
'.omnivore-toast-func-row'
|
||||||
|
)
|
||||||
|
|
||||||
|
rows?.forEach((r) => {
|
||||||
|
r.setAttribute('data-state', 'closed')
|
||||||
|
})
|
||||||
|
|
||||||
|
if (container && initialState) {
|
||||||
|
const newState = initialState === 'open' ? 'closed' : 'open'
|
||||||
|
container.setAttribute('data-state', newState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteCacheKey = () => {
|
||||||
|
return `cached-note-${document.location.href}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getClientRequestId = () => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const clientRequestId = currentToastEl?.getAttribute(
|
||||||
|
'data-omnivore-client-request-id'
|
||||||
|
)
|
||||||
|
return clientRequestId
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Button functions
|
||||||
|
//
|
||||||
|
|
||||||
|
const login = () => {
|
||||||
|
window.open(new URL(`/login`, process.env.OMNIVORE_URL), '_blank')
|
||||||
|
closeToolbarLater()
|
||||||
|
}
|
||||||
|
|
||||||
|
const openMenu = () => {
|
||||||
|
cancelAutoDismiss()
|
||||||
|
toggleRow('#omnivore-extra-buttons-row')
|
||||||
|
}
|
||||||
|
|
||||||
|
const addNote = async () => {
|
||||||
|
console.log('[omnivore] adding note')
|
||||||
|
cancelAutoDismiss()
|
||||||
|
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const clientRequestId = currentToastEl?.getAttribute(
|
||||||
|
'data-omnivore-client-request-id'
|
||||||
|
)
|
||||||
|
console.log('client request id: ', clientRequestId)
|
||||||
|
if (!clientRequestId) {
|
||||||
|
// TODO: move into an error state
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'failure',
|
||||||
|
'Error adding note...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const cachedNoteKey = noteCacheKey()
|
||||||
|
|
||||||
|
cancelAutoDismiss()
|
||||||
|
toggleRow('#omnivore-add-note-row')
|
||||||
|
|
||||||
|
const noteArea =
|
||||||
|
currentToastEl?.shadowRoot?.querySelector<HTMLTextAreaElement>(
|
||||||
|
'#omnivore-add-note-textarea'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (noteArea) {
|
||||||
|
if (cachedNoteKey) {
|
||||||
|
const existingNote =
|
||||||
|
((await getStorageItem(cachedNoteKey)) as string) ?? ''
|
||||||
|
noteArea.value = existingNote
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noteArea.value) {
|
||||||
|
noteArea.select()
|
||||||
|
} else {
|
||||||
|
noteArea.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
noteArea.addEventListener('input', async (event) => {
|
||||||
|
const note: Record<string, string> = {}
|
||||||
|
note[cachedNoteKey] = (event.target as HTMLTextAreaElement).value
|
||||||
|
await setStorage(note)
|
||||||
|
})
|
||||||
|
|
||||||
|
noteArea.onkeydown = async (e: KeyboardEvent) => {
|
||||||
|
// e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
// Handle the enter key
|
||||||
|
console.log('handling the enter key: ', e.keyCode)
|
||||||
|
if (e.keyCode == 13 && (e.metaKey || e.ctrlKey)) {
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'waiting',
|
||||||
|
'Adding note...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
await saveNote(clientRequestId, noteArea.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = currentToastEl?.shadowRoot?.querySelector<HTMLElement>(
|
||||||
|
'#omnivore-add-note-form'
|
||||||
|
)
|
||||||
|
|
||||||
|
if (form) {
|
||||||
|
form.onsubmit = async (event) => {
|
||||||
|
console.log('handling form submit')
|
||||||
|
updateStatusBox(
|
||||||
|
'#omnivore-add-note-status',
|
||||||
|
'waiting',
|
||||||
|
'Adding note...',
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
|
||||||
|
if (noteArea) {
|
||||||
|
await saveNote(clientRequestId, noteArea.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const archive = async (event: Event) => {
|
||||||
|
const clientRequestId = getClientRequestId()
|
||||||
|
try {
|
||||||
|
await chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'archive',
|
||||||
|
clientRequestId,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error archiving item')
|
||||||
|
}
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteItem = async (event: Event) => {
|
||||||
|
const clientRequestId = getClientRequestId()
|
||||||
|
try {
|
||||||
|
await chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'delete',
|
||||||
|
clientRequestId,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error archiving item')
|
||||||
|
}
|
||||||
|
event.preventDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
const readNow = async () => {
|
||||||
|
cancelAutoDismiss()
|
||||||
|
|
||||||
|
let currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
const container = currentToastEl?.shadowRoot?.querySelector(
|
||||||
|
'#omnivore-toast-container'
|
||||||
|
)
|
||||||
|
container?.setAttribute('data-state', 'open')
|
||||||
|
|
||||||
|
window.open(
|
||||||
|
new URL(
|
||||||
|
`/article?url=${encodeURI(document.location.href)}`,
|
||||||
|
(await getStorageItem("omnivoreUrl")) as string,
|
||||||
|
),
|
||||||
|
'_blank'
|
||||||
|
)
|
||||||
|
|
||||||
|
closeToolbarLater()
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeToolbarLater = () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
closeToolbar()
|
||||||
|
}, 1000)
|
||||||
|
}
|
||||||
|
const closeToolbar = () => {
|
||||||
|
const currentToastEl = document.querySelector('#omnivore-extension-root')
|
||||||
|
if (currentToastEl) {
|
||||||
|
currentToastEl.remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// API interactions
|
||||||
|
//
|
||||||
|
|
||||||
|
const saveNote = async (clientRequestId: string, note: string) => {
|
||||||
|
try {
|
||||||
|
await chrome.runtime.sendMessage({
|
||||||
|
action: 'enqueueTask',
|
||||||
|
task: 'addNote',
|
||||||
|
note,
|
||||||
|
clientRequestId,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error adding note: ', err)
|
||||||
|
}
|
||||||
|
}
|
||||||
528
pkg/extension-v3/src/scripts/omnivore-api.ts
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
import { ArticleData, Label, SavePageData, SetLinkArchivedData } from './types'
|
||||||
|
import { getStorageItem, setStorage } from './utils'
|
||||||
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
|
import { nanoid } from 'nanoid'
|
||||||
|
|
||||||
|
export type ApiResult = 'success' | 'failure' | 'unauthorized'
|
||||||
|
|
||||||
|
const gqlRequest = async (query: string) => {
|
||||||
|
const apiKey = (await getStorageItem('omnivoreApiKey')) as string | undefined
|
||||||
|
let headers = {
|
||||||
|
Accept: 'application/json',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
} as Record<string, string>
|
||||||
|
if (apiKey) {
|
||||||
|
headers['Authorization'] = apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const apiUrl= (await getStorageItem('omnivoreApiUrl')) as string | undefined
|
||||||
|
?? process.env.OMNIVORE_GRAPHQL_URL
|
||||||
|
?? ''
|
||||||
|
|
||||||
|
console.log(apiUrl)
|
||||||
|
const response = await fetch(`${apiUrl}/api/graphql`, {
|
||||||
|
method: 'POST',
|
||||||
|
redirect: 'follow',
|
||||||
|
credentials: 'include',
|
||||||
|
mode: 'cors',
|
||||||
|
headers,
|
||||||
|
body: query,
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
if (!('data' in json) || !json.data) {
|
||||||
|
throw new Error('No response data')
|
||||||
|
}
|
||||||
|
return json.data
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[omnivore] error making api request: ', query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function savePageRequest(input: {
|
||||||
|
url: string
|
||||||
|
title: string
|
||||||
|
clientRequestId: string
|
||||||
|
originalContent: string
|
||||||
|
}) {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `mutation SavePage ($input: SavePageInput!) {
|
||||||
|
savePage(input:$input){
|
||||||
|
... on SaveSuccess {
|
||||||
|
url
|
||||||
|
clientRequestId
|
||||||
|
}
|
||||||
|
... on SaveError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
source: 'extension',
|
||||||
|
...input,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = (await gqlRequest(mutation)) as SavePageData
|
||||||
|
if (data.savePage?.errorCodes?.length) {
|
||||||
|
console.log('[omnivore] api: error saving page:', data)
|
||||||
|
if (data.savePage.errorCodes.indexOf('UNAUTHORIZED') > -1) {
|
||||||
|
console.log('[omnivore] api is not authorized')
|
||||||
|
return { result: 'unauthorized' }
|
||||||
|
}
|
||||||
|
return { result: 'failure' }
|
||||||
|
}
|
||||||
|
return { result: 'success', libraryItemId: data.savePage?.clientRequestId }
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function addNoteToLibraryItem(input: {
|
||||||
|
libraryItemId: string
|
||||||
|
note: string
|
||||||
|
}) {
|
||||||
|
const query = JSON.stringify({
|
||||||
|
query: `query GetArticle(
|
||||||
|
$username: String!
|
||||||
|
$slug: String!
|
||||||
|
$includeFriendsHighlights: Boolean
|
||||||
|
) {
|
||||||
|
article(username: $username, slug: $slug) {
|
||||||
|
... on ArticleSuccess {
|
||||||
|
article {
|
||||||
|
highlights(input: { includeFriends: $includeFriendsHighlights }) {
|
||||||
|
...HighlightFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on ArticleError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment HighlightFields on Highlight {
|
||||||
|
id
|
||||||
|
type
|
||||||
|
annotation
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
username: 'me',
|
||||||
|
slug: input.libraryItemId,
|
||||||
|
includeFriendsHighlights: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = (await gqlRequest(query)) as ArticleData
|
||||||
|
if (data.article?.errorCodes?.length) {
|
||||||
|
console.log('[omnivore] api: error getting article:', data)
|
||||||
|
if (data.article.errorCodes.indexOf('UNAUTHORIZED') > -1) {
|
||||||
|
console.log('[omnivore] api is not authorized')
|
||||||
|
return 'unauthorized'
|
||||||
|
}
|
||||||
|
return 'failure'
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('DATA.ARTICLE: ', data.article)
|
||||||
|
const existingNote = data.article?.highlights?.find((h) => h.type == 'NOTE')
|
||||||
|
|
||||||
|
if (existingNote) {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `
|
||||||
|
mutation UpdateHighlight($input: UpdateHighlightInput!) {
|
||||||
|
updateHighlight(input: $input) {
|
||||||
|
... on UpdateHighlightSuccess {
|
||||||
|
highlight {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on UpdateHighlightError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
highlightId: existingNote.id,
|
||||||
|
annotation: existingNote.annotation
|
||||||
|
? existingNote.annotation + '\n\n' + input.note
|
||||||
|
: input.note,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const result = await gqlRequest(mutation)
|
||||||
|
if (
|
||||||
|
!result.updateHighlight ||
|
||||||
|
result.updateHighlight['errorCodes'] ||
|
||||||
|
!result.updateHighlight.highlight
|
||||||
|
) {
|
||||||
|
console.log('GQL Error updating note:', result)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return result.updateHighlight.highlight.id
|
||||||
|
} else {
|
||||||
|
const noteId = uuidv4()
|
||||||
|
const shortId = nanoid(8)
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `
|
||||||
|
mutation CreateHighlight($input: CreateHighlightInput!) {
|
||||||
|
createHighlight(input: $input) {
|
||||||
|
... on CreateHighlightSuccess {
|
||||||
|
highlight {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on CreateHighlightError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
id: noteId,
|
||||||
|
shortId: shortId,
|
||||||
|
type: 'NOTE',
|
||||||
|
articleId: input.libraryItemId,
|
||||||
|
annotation: input.note,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const result = await gqlRequest(mutation)
|
||||||
|
if (
|
||||||
|
!result.createHighlight ||
|
||||||
|
result.createHighlight['errorCodes'] ||
|
||||||
|
!result.createHighlight.highlight
|
||||||
|
) {
|
||||||
|
console.log('GQL Error setting note:', result)
|
||||||
|
return 'failure'
|
||||||
|
}
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateLabelsCache(): Promise<Label[]> {
|
||||||
|
const query = JSON.stringify({
|
||||||
|
query: `query GetLabels {
|
||||||
|
labels {
|
||||||
|
... on LabelsSuccess {
|
||||||
|
labels {
|
||||||
|
...LabelFields
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on LabelsError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fragment LabelFields on Label {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
color
|
||||||
|
description
|
||||||
|
createdAt
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await gqlRequest(query)
|
||||||
|
if (!data.labels || data.labels['errorCodes'] || !data.labels['labels']) {
|
||||||
|
console.log('GQL Error updating label cache response:', data, data)
|
||||||
|
console.log(!data.labels, data.labels['errorCodes'], !data.labels['labels'])
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
await setStorage({
|
||||||
|
labels: data.labels.labels,
|
||||||
|
labelsLastUpdated: new Date().toISOString(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return data.labels.labels
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updatePageTitle(pageId: string, title: string) {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `mutation UpdatePage($input: UpdatePageInput!) {
|
||||||
|
updatePage(input: $input) {
|
||||||
|
... on UpdatePageSuccess {
|
||||||
|
updatedPage {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on UpdatePageError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
pageId,
|
||||||
|
title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await gqlRequest(mutation)
|
||||||
|
console.log(data);
|
||||||
|
if (
|
||||||
|
!data.updatePage ||
|
||||||
|
data.updatePage['errorCodes'] ||
|
||||||
|
!data.updatePage['updatedPage']
|
||||||
|
) {
|
||||||
|
console.log('GQL Error updating page:', data)
|
||||||
|
throw new Error('Error updating title.')
|
||||||
|
}
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function setLabels(pageId: string, labels: string[]) {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `mutation SetLabels($input: SetLabelsInput!) {
|
||||||
|
setLabels(input: $input) {
|
||||||
|
... on SetLabelsSuccess {
|
||||||
|
labels {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on SetLabelsError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
pageId,
|
||||||
|
labelIds: labels,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await gqlRequest(mutation)
|
||||||
|
if (
|
||||||
|
!data.setLabels ||
|
||||||
|
data.setLabels['errorCodes'] ||
|
||||||
|
!data.setLabels['labels']
|
||||||
|
) {
|
||||||
|
console.log('GQL Error setting labels:', data)
|
||||||
|
throw new Error('Error setting labels.')
|
||||||
|
}
|
||||||
|
|
||||||
|
return data.setLabels.labels
|
||||||
|
}
|
||||||
|
|
||||||
|
// async function appendLabelsToCache(labels) {
|
||||||
|
// const cachedLabels = await getStorageItem('labels')
|
||||||
|
// if (cachedLabels) {
|
||||||
|
// labels.forEach((l) => {
|
||||||
|
// const existing = cachedLabels.find((cached) => cached.name === l.name)
|
||||||
|
// if (!existing) {
|
||||||
|
// cachedLabels.unshift(l)
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// await setStorage({
|
||||||
|
// labels: cachedLabels,
|
||||||
|
// labelsLastUpdated: new Date().toISOString(),
|
||||||
|
// })
|
||||||
|
// } else {
|
||||||
|
// await setStorage({
|
||||||
|
// labels: labels,
|
||||||
|
// labelsLastUpdated: new Date().toISOString(),
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function addNote(apiUrl, pageId, noteId, shortId, note) {
|
||||||
|
// const query = JSON.stringify({
|
||||||
|
// query: `query GetArticle(
|
||||||
|
// $username: String!
|
||||||
|
// $slug: String!
|
||||||
|
// $includeFriendsHighlights: Boolean
|
||||||
|
// ) {
|
||||||
|
// article(username: $username, slug: $slug) {
|
||||||
|
// ... on ArticleSuccess {
|
||||||
|
// article {
|
||||||
|
// highlights(input: { includeFriends: $includeFriendsHighlights }) {
|
||||||
|
// ...HighlightFields
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ... on ArticleError {
|
||||||
|
// errorCodes
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// fragment HighlightFields on Highlight {
|
||||||
|
// id
|
||||||
|
// type
|
||||||
|
// annotation
|
||||||
|
// }
|
||||||
|
// `,
|
||||||
|
// variables: {
|
||||||
|
// username: 'me',
|
||||||
|
// slug: pageId,
|
||||||
|
// includeFriendsHighlights: false,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const data = await gqlRequest(apiUrl, query)
|
||||||
|
// if (!data.article || data.article['errorCodes'] || !data.article['article']) {
|
||||||
|
// console.log('GQL Error getting existing highlights:', data)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// const existingNote = data.article.article.highlights.find(
|
||||||
|
// (h) => h.type == 'NOTE'
|
||||||
|
// )
|
||||||
|
|
||||||
|
// if (existingNote) {
|
||||||
|
// const mutation = JSON.stringify({
|
||||||
|
// query: `
|
||||||
|
// mutation UpdateHighlight($input: UpdateHighlightInput!) {
|
||||||
|
// updateHighlight(input: $input) {
|
||||||
|
// ... on UpdateHighlightSuccess {
|
||||||
|
// highlight {
|
||||||
|
// id
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ... on UpdateHighlightError {
|
||||||
|
// errorCodes
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// `,
|
||||||
|
// variables: {
|
||||||
|
// input: {
|
||||||
|
// highlightId: existingNote.id,
|
||||||
|
// annotation: existingNote.annotation
|
||||||
|
// ? existingNote.annotation + '\n\n' + note
|
||||||
|
// : note,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// const result = await gqlRequest(apiUrl, mutation)
|
||||||
|
// if (
|
||||||
|
// !result.updateHighlight ||
|
||||||
|
// result.updateHighlight['errorCodes'] ||
|
||||||
|
// !result.updateHighlight.highlight
|
||||||
|
// ) {
|
||||||
|
// console.log('GQL Error updating note:', result)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// return result.updateHighlight.highlight.id
|
||||||
|
// } else {
|
||||||
|
// const mutation = JSON.stringify({
|
||||||
|
// query: `
|
||||||
|
// mutation CreateHighlight($input: CreateHighlightInput!) {
|
||||||
|
// createHighlight(input: $input) {
|
||||||
|
// ... on CreateHighlightSuccess {
|
||||||
|
// highlight {
|
||||||
|
// id
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ... on CreateHighlightError {
|
||||||
|
// errorCodes
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// `,
|
||||||
|
// variables: {
|
||||||
|
// input: {
|
||||||
|
// id: noteId,
|
||||||
|
// shortId: shortId,
|
||||||
|
// type: 'NOTE',
|
||||||
|
// articleId: pageId,
|
||||||
|
// annotation: note,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// const result = await gqlRequest(apiUrl, mutation)
|
||||||
|
// if (
|
||||||
|
// !result.createHighlight ||
|
||||||
|
// result.createHighlight['errorCodes'] ||
|
||||||
|
// !result.createHighlight.highlight
|
||||||
|
// ) {
|
||||||
|
// console.log('GQL Error setting note:', result)
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// return result.createHighlight.highlight.id
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
export const archiveLibraryItem = async (
|
||||||
|
libraryItemId: string
|
||||||
|
): Promise<ApiResult> => {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `mutation SetLinkArchived($input: ArchiveLinkInput!) {
|
||||||
|
setLinkArchived(input: $input) {
|
||||||
|
... on ArchiveLinkSuccess {
|
||||||
|
linkId
|
||||||
|
message
|
||||||
|
}
|
||||||
|
... on ArchiveLinkError {
|
||||||
|
message
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
linkId: libraryItemId,
|
||||||
|
archived: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = (await gqlRequest(mutation)) as SetLinkArchivedData
|
||||||
|
if (data.setLinkArchived?.errorCodes?.length) {
|
||||||
|
console.log('[omnivore] api: error getting article:', data)
|
||||||
|
if (data.setLinkArchived.errorCodes.indexOf('UNAUTHORIZED') > -1) {
|
||||||
|
console.log('[omnivore] api is not authorized')
|
||||||
|
return 'unauthorized'
|
||||||
|
}
|
||||||
|
return 'failure'
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteItem(pageId: string) {
|
||||||
|
const mutation = JSON.stringify({
|
||||||
|
query: `mutation SetBookmarkArticle($input: SetBookmarkArticleInput!) {
|
||||||
|
setBookmarkArticle(input: $input) {
|
||||||
|
... on SetBookmarkArticleSuccess {
|
||||||
|
bookmarkedArticle {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on SetBookmarkArticleError {
|
||||||
|
errorCodes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables: {
|
||||||
|
input: {
|
||||||
|
articleID: pageId,
|
||||||
|
bookmark: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await gqlRequest(mutation)
|
||||||
|
if (
|
||||||
|
!data.setBookmarkArticle ||
|
||||||
|
data.setBookmarkArticle['errorCodes'] ||
|
||||||
|
!data.setBookmarkArticle.bookmarkedArticle
|
||||||
|
) {
|
||||||
|
console.log('GQL Error deleting:', data)
|
||||||
|
throw new Error('Error deleting.')
|
||||||
|
}
|
||||||
|
return 'success'
|
||||||
|
}
|
||||||
112
pkg/extension-v3/src/scripts/types.ts
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
export type ToolbarStatus = 'waiting' | 'success' | 'failure'
|
||||||
|
|
||||||
|
export interface ToolbarMessage {
|
||||||
|
status?: ToolbarStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SavePageData {
|
||||||
|
savePage?: SavePageResult
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SavePageResult {
|
||||||
|
url?: string
|
||||||
|
clientRequestId?: string
|
||||||
|
errorCodes?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Highlight {
|
||||||
|
id: string
|
||||||
|
type: string
|
||||||
|
annotation: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ArticleResult {
|
||||||
|
highlights?: Highlight[]
|
||||||
|
errorCodes?: string[]
|
||||||
|
}
|
||||||
|
export interface ArticleData {
|
||||||
|
article?: ArticleResult
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetLinkArchivedResult {
|
||||||
|
linkId?: string
|
||||||
|
message?: string
|
||||||
|
errorCodes?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetLinkArchivedData {
|
||||||
|
setLinkArchived?: SetLinkArchivedResult
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SavePageInput {
|
||||||
|
url: string
|
||||||
|
title: string
|
||||||
|
clientRequestId: string
|
||||||
|
originalContent: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddNoteInput {
|
||||||
|
clientRequestId: string
|
||||||
|
note: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TaskInput {
|
||||||
|
clientRequestId: string
|
||||||
|
libraryItemId?: string | undefined
|
||||||
|
task: 'addNote' | 'archive' | 'editTitle' | 'delete' | 'updateLabelCache' | 'setLabels'
|
||||||
|
title?: string | undefined
|
||||||
|
note?: string | undefined
|
||||||
|
labels?: string[] | undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Label {
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
color: string
|
||||||
|
selected: 'on' | 'off'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSavePageResult(obj: any): obj is SavePageResult {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
(obj.url === undefined || typeof obj.url === 'string') &&
|
||||||
|
(obj.clientRequestId === undefined ||
|
||||||
|
typeof obj.clientRequestId === 'string') &&
|
||||||
|
(obj.errorCodes === undefined ||
|
||||||
|
(Array.isArray(obj.errorCodes) &&
|
||||||
|
obj.errorCodes.every((code: any) => typeof code === 'string')))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSavePageData(obj: any): obj is SavePageData {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
(obj.savePage === undefined || isSavePageResult(obj.savePage))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSavePageInput(obj: any): obj is SavePageInput {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
typeof obj.url === 'string' &&
|
||||||
|
typeof obj.title === 'string' &&
|
||||||
|
typeof obj.clientRequestId === 'string' &&
|
||||||
|
typeof obj.originalContent === 'string'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAddNoteInput(obj: any): obj is AddNoteInput {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
typeof obj.note === 'string' &&
|
||||||
|
typeof obj.clientRequestId === 'string'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isEnqueueTaskMessage(obj: any): obj is TaskInput {
|
||||||
|
return (
|
||||||
|
typeof obj === 'object' &&
|
||||||
|
typeof obj.task === 'string' &&
|
||||||
|
typeof obj.clientRequestId === 'string'
|
||||||
|
)
|
||||||
|
}
|
||||||
18
pkg/extension-v3/src/scripts/utils.ts
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
export const getStorageItem = async (singleKey: string) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
chrome.storage.local.get(singleKey, (result) => {
|
||||||
|
const finalResult = (result && result[singleKey]) || null
|
||||||
|
resolve(finalResult)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setStorage = (itemsToSet: Record<string, string>) => {
|
||||||
|
return chrome.storage.local.set(itemsToSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// function removeStorage(itemsToRemove) {
|
||||||
|
// return new Promise((resolve) => {
|
||||||
|
// browserApi.storage.local.remove(itemsToRemove, resolve)
|
||||||
|
// })
|
||||||
|
// }
|
||||||
126
pkg/extension-v3/src/task-queue.ts
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
import {
|
||||||
|
addNoteToLibraryItem,
|
||||||
|
archiveLibraryItem,
|
||||||
|
deleteItem, setLabels, updateLabelsCache,
|
||||||
|
updatePageTitle
|
||||||
|
} from './scripts/omnivore-api'
|
||||||
|
import { TaskInput } from './scripts/types'
|
||||||
|
|
||||||
|
export class TaskQueue {
|
||||||
|
private queue: Array<TaskInput> = []
|
||||||
|
private isRunning: boolean = false
|
||||||
|
private isReady: boolean = false
|
||||||
|
|
||||||
|
private tabId: number | undefined
|
||||||
|
private libraryItemId: string | undefined
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
enqueue(task: TaskInput): void {
|
||||||
|
this.queue.push(task)
|
||||||
|
|
||||||
|
// Only run the next task if the queue is ready
|
||||||
|
if (this.isReady) {
|
||||||
|
this.runNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async runNext(): Promise<void> {
|
||||||
|
if (this.isRunning || this.queue.length === 0 || !this.isReady) return
|
||||||
|
|
||||||
|
this.isRunning = true
|
||||||
|
const task = this.queue.shift()
|
||||||
|
|
||||||
|
if (task) {
|
||||||
|
try {
|
||||||
|
await this.executeTask(task)
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Task failed:', err)
|
||||||
|
} finally {
|
||||||
|
this.isRunning = false
|
||||||
|
if (this.isReady) {
|
||||||
|
this.runNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private executeTask = async (task: TaskInput) => {
|
||||||
|
console.log('executing task: ', task)
|
||||||
|
if (!this.libraryItemId) {
|
||||||
|
throw Error('Attempting to execute queue that is not ready.')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let success = false
|
||||||
|
switch (task.task) {
|
||||||
|
case 'archive': {
|
||||||
|
await archiveLibraryItem(this.libraryItemId)
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'delete': {
|
||||||
|
await deleteItem(this.libraryItemId)
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'addNote': {
|
||||||
|
await addNoteToLibraryItem({
|
||||||
|
note: task.note || '',
|
||||||
|
libraryItemId: this.libraryItemId,
|
||||||
|
})
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'setLabels':
|
||||||
|
await setLabels(this.libraryItemId, task.labels ?? [])
|
||||||
|
success = true;
|
||||||
|
break
|
||||||
|
case 'editTitle': {
|
||||||
|
if (!task.title || !this.libraryItemId) {
|
||||||
|
throw new Error("Title not set, or library item not yet saved.")
|
||||||
|
}
|
||||||
|
|
||||||
|
await updatePageTitle(this.libraryItemId, task.title)
|
||||||
|
success = true
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'updateLabelCache': {
|
||||||
|
await updateLabelsCache()
|
||||||
|
if (this.tabId) {
|
||||||
|
chrome.tabs.sendMessage(this.tabId, {
|
||||||
|
message: 'updateLabelCache',
|
||||||
|
status: 'success',
|
||||||
|
task: task.task,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success && this.tabId) {
|
||||||
|
chrome.tabs.sendMessage(this.tabId, {
|
||||||
|
message: 'updateToolbar',
|
||||||
|
status: 'success',
|
||||||
|
task: task.task,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log('[omnivore] task queue error: ', err)
|
||||||
|
if (this.tabId) {
|
||||||
|
console.log('sending error message')
|
||||||
|
chrome.tabs.sendMessage(this.tabId, {
|
||||||
|
message: 'updateToolbar',
|
||||||
|
status: 'failure',
|
||||||
|
task: task.task,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setReady(tabId: number, libraryItemId: string): void {
|
||||||
|
console.log('setting ready')
|
||||||
|
this.tabId = tabId
|
||||||
|
this.libraryItemId = libraryItemId
|
||||||
|
this.isReady = true
|
||||||
|
this.runNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
36
pkg/extension-v3/src/views/options.html
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Omnivore Extension Settings</title>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class='wrapper'>
|
||||||
|
<h1>API Key</h1>
|
||||||
|
|
||||||
|
<label for="api-key">API Key:</label>
|
||||||
|
|
||||||
|
<input type="text" id="api-key" style="width: 95%">
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
<button id="save-api-key-btn">Save API Key</button>
|
||||||
|
|
||||||
|
|
||||||
|
<h1>API URL</h1>
|
||||||
|
|
||||||
|
<label for="api-url">API URL:</label>
|
||||||
|
<input type="text" id="api-url" style="width: 95%">
|
||||||
|
<br><br>
|
||||||
|
<button id="save-api-url-btn">Save API URL</button>
|
||||||
|
|
||||||
|
<h1>OMNIVORE URL</h1>
|
||||||
|
|
||||||
|
<label for="omnivore-url">API URL:</label>
|
||||||
|
<input type="text" id="omnivore-url" style="width: 95%">
|
||||||
|
<br><br>
|
||||||
|
<button id="save-omnivore-url-btn">Save Omnivore URL</button>
|
||||||
|
|
||||||
|
<script src="options.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
46
pkg/extension-v3/src/views/options.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
function addStorage(itemsToAdd) {
|
||||||
|
return chrome.storage.local.set(itemsToAdd)
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const saveApiButton = document.getElementById('save-api-key-btn')
|
||||||
|
const apiInput = document.getElementById('api-key')
|
||||||
|
|
||||||
|
|
||||||
|
chrome.storage.local.get('omnivoreApiKey').then(
|
||||||
|
apiKey => {
|
||||||
|
apiInput.value = apiKey.omnivoreApiKey ?? ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
saveApiButton.addEventListener('click', (e) => {
|
||||||
|
addStorage({ "omnivoreApiKey": apiInput.value })
|
||||||
|
})
|
||||||
|
|
||||||
|
const saveUrlButton = document.getElementById('save-api-url-btn')
|
||||||
|
const apiUrlInput = document.getElementById('api-url')
|
||||||
|
|
||||||
|
chrome.storage.local.get('omnivoreApiUrl').then(
|
||||||
|
url => {
|
||||||
|
apiUrlInput.value = url.omnivoreApiUrl ?? ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
saveUrlButton.addEventListener('click', (e) => {
|
||||||
|
addStorage({ "omnivoreApiUrl": apiUrlInput.value })
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const urlButton = document.getElementById('save-omnivore-url-btn')
|
||||||
|
const urlInput = document.getElementById('omnivore-url')
|
||||||
|
|
||||||
|
chrome.storage.local.get('omnivoreUrl').then(
|
||||||
|
url => {
|
||||||
|
urlInput.value = url.omnivoreUrl ?? ''
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
urlButton.addEventListener('click', (e) => {
|
||||||
|
addStorage({ "omnivoreUrl": urlInput.value })
|
||||||
|
})
|
||||||
|
});
|
||||||
555
pkg/extension-v3/src/views/toast.html
Normal file
@ -0,0 +1,555 @@
|
|||||||
|
<style>
|
||||||
|
#omnivore-toast-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: flex-end;
|
||||||
|
overflow: hidden;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #3D3D3D;
|
||||||
|
background: #fff;
|
||||||
|
font: 400 12px sans-serif;
|
||||||
|
line-height: 20px;
|
||||||
|
box-shadow: 0px 5px 20px rgba(32, 31, 29, 0.12);
|
||||||
|
transition: all 300ms ease;
|
||||||
|
z-index: 9999999;
|
||||||
|
width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container input, select, textarea{
|
||||||
|
color: #3D3D3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 0px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button {
|
||||||
|
padding-left: 10px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-logged-out-row {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row[data-state="open"] {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row[data-state="closed"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
color:#898989;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-status {
|
||||||
|
height: 22px;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-button-row {
|
||||||
|
gap: 5px;
|
||||||
|
align-items: center;
|
||||||
|
padding-top: 7px;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
color: #898989;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 5px;
|
||||||
|
height: 30px;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button:hover {
|
||||||
|
color: #3B3A38;
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container .omnivore-save-button button {
|
||||||
|
background-color: rgb(255, 210, 52)
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn:hover {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn svg {
|
||||||
|
fill: #3D3D3D;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn:hover > svg *,
|
||||||
|
#omnivore-toast-container #omnivore-toast-close-btn svg:hover {
|
||||||
|
fill: #D9D9D9;
|
||||||
|
stroke: white;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container svg {
|
||||||
|
fill: #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container > svg *,
|
||||||
|
#omnivore-toast-container svg:hover {
|
||||||
|
fill: #3B3A38;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-edit-title-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-delete-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container form {
|
||||||
|
display: block;
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
.omnivore-toast-divider {
|
||||||
|
height:20px;
|
||||||
|
border-right: 1px solid #D9D9D9;
|
||||||
|
}
|
||||||
|
.omnivore-toast-statusBox {
|
||||||
|
display: flex;
|
||||||
|
width: 20px;
|
||||||
|
margin-left: 0px;
|
||||||
|
margin-right: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-title-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-title-row textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
padding: 5px;
|
||||||
|
resize: none;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
padding: 5px;
|
||||||
|
resize: none;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row button {
|
||||||
|
height: 30px;
|
||||||
|
padding: 15px;
|
||||||
|
margin-left: auto;
|
||||||
|
background-color: #FFEA9F;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row {
|
||||||
|
flex-direction: column;
|
||||||
|
visibility: unset;
|
||||||
|
padding-top: 20px;
|
||||||
|
height: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row input {
|
||||||
|
width: 100%;
|
||||||
|
height: 34px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #8E8E93;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-extra-buttons-row {
|
||||||
|
flex-direction: column;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button {
|
||||||
|
align-self: flex-start;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-list {
|
||||||
|
overflow-y: scroll;
|
||||||
|
max-height: 200px;
|
||||||
|
gap: 5px;
|
||||||
|
color: #3B3A38;
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
height: 35px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
background: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button[data-label-selected="on"] .checkbox {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button[data-label-selected="off"] .checkbox {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:focus-visible {
|
||||||
|
outline: unset;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-list div:hover {
|
||||||
|
background-color: #EBEBEB;
|
||||||
|
}
|
||||||
|
#omnivore-edit-labels-row form {
|
||||||
|
margin-bottom: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-add-note-row textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row input, select, textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
#omnivore-edit-title-row textarea:focus-visible {
|
||||||
|
border-color: #2f81f7;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.omnivore-toast-menu-divider {
|
||||||
|
border-bottom: 1px solid #D9D9D9;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-login-btn {
|
||||||
|
color: #898989;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
#omnivore-toast-container {
|
||||||
|
background: #333333;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container input, select, textarea{
|
||||||
|
color: #D9D9D9;
|
||||||
|
}
|
||||||
|
.omnivore-toast-divider {
|
||||||
|
border-right: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container svg {
|
||||||
|
fill: #898989;
|
||||||
|
}
|
||||||
|
.omnivore-save-button button {
|
||||||
|
margin-top: 10px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container button:hover > svg *,
|
||||||
|
#omnivore-toast-container button:hover {
|
||||||
|
color: #D9D9D9;
|
||||||
|
fill: #D9D9D9;
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button:hover {
|
||||||
|
color: #D9D9D9;
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-extra-buttons-row button:hover {
|
||||||
|
background-color: #2A2A2A;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-edit-labels-list button {
|
||||||
|
border-bottom: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-edit-title-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
#omnivore-toast-container #omnivore-toast-delete-btn > svg * {
|
||||||
|
fill: none;
|
||||||
|
}
|
||||||
|
.omnivore-toast-menu-divider {
|
||||||
|
border-bottom: 1px solid #898989;
|
||||||
|
}
|
||||||
|
#omnivore-toast-login-btn {
|
||||||
|
color: #898989;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
.label-editor {
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
|
||||||
|
display: inline-block;
|
||||||
|
background-color: var(--colors-thBackground2);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 5px;
|
||||||
|
line-height: 2;
|
||||||
|
cursor: text;
|
||||||
|
font-size: 12px;
|
||||||
|
width: calc(100% - 10px);
|
||||||
|
min-height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label-list {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: start;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: auto;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin: 0;
|
||||||
|
list-style: none;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row .label-remove-button {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: transparent;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-edit-labels-row .label-input {
|
||||||
|
box-sizing: content-box;
|
||||||
|
font-size: 16px;
|
||||||
|
min-width: 2px;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
padding: 0px;
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
display: inline-table;
|
||||||
|
padding: 1px;
|
||||||
|
padding-left: 7px;
|
||||||
|
padding-right: 7px;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
border: 1px solid rgb(222, 222, 222);
|
||||||
|
background-color: rgb(249, 249, 249);
|
||||||
|
}
|
||||||
|
|
||||||
|
#omnivore-toast-container .omnivore-toast-func-row .label button {
|
||||||
|
height: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label[data-label-backspaced="on"] {
|
||||||
|
border: 1px solid rgb(255, 234, 159);
|
||||||
|
}
|
||||||
|
|
||||||
|
.label[data-item-highlighted="on"] {
|
||||||
|
border: 1px solid black;
|
||||||
|
transition: border-color 0.25s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
/* control spinner size with setting font-size */
|
||||||
|
font-size: 3rem;
|
||||||
|
border: 2px solid #FFD234;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
animation: loading-spinner 1.5s linear infinite;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loading-spinner {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<div id="omnivore-toast-container">
|
||||||
|
<div id="omnivore-toast-button-row">
|
||||||
|
<span class="omnivore-toast-statusBox">
|
||||||
|
<div class="loading-spinner"></div>
|
||||||
|
</span>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button class="omnivore-top-button" id="omnivore-toast-add-note-btn">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 256 256">
|
||||||
|
<path d="M88,96a8,8,0,0,1,8-8h64a8,8,0,0,1,0,16H96A8,8,0,0,1,88,96Zm8,40h64a8,8,0,0,0,0-16H96a8,8,0,0,0,0,16Zm32,16H96a8,8,0,0,0,0,16h32a8,8,0,0,0,0-16ZM224,48V156.69A15.86,15.86,0,0,1,219.31,168L168,219.31A15.86,15.86,0,0,1,156.69,224H48a16,16,0,0,1-16-16V48A16,16,0,0,1,48,32H208A16,16,0,0,1,224,48ZM48,208H152V160a8,8,0,0,1,8-8h48V48H48Zm120-40v28.7L196.69,168Z"></path>
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Add Note</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-edit-labels-btn">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.99031 14.9786L15.3061 8.67029C15.3757 8.6002 15.4307 8.51707 15.468 8.42568C15.5053 8.33429 15.5242 8.23643 15.5237 8.13772L15.5237 1.38683C15.5237 1.18789 15.4446 0.997101 15.304 0.85643C15.1633 0.715759 14.9725 0.636731 14.7736 0.636731L8.02269 0.636731C7.92397 0.63616 7.82611 0.655082 7.73472 0.69241C7.64333 0.729738 7.5602 0.784739 7.49012 0.85426L1.18179 7.17009C0.76038 7.59202 0.523681 8.16397 0.523681 8.7603C0.523681 9.35663 0.76038 9.92857 1.18179 10.3505L5.77239 14.9786C6.19432 15.4 6.76627 15.6367 7.3626 15.6367C7.95893 15.6367 8.53087 15.4 8.95281 14.9786L8.99031 14.9786ZM6.87503 13.921L2.24693 9.28536C2.10722 9.14482 2.0288 8.95471 2.0288 8.75655C2.0288 8.55838 2.10722 8.36827 2.24693 8.22773L8.33022 2.13693L14.0235 2.13693L14.0235 7.83018L7.93267 13.921C7.86258 13.9905 7.77946 14.0455 7.68807 14.0828C7.59668 14.1202 7.49882 14.1391 7.4001 14.1385C7.20332 14.1377 7.01475 14.0595 6.87503 13.921Z" />
|
||||||
|
<circle cx="10.8818" cy="5.48069" r="1.24925" />
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Set Labels</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-read-now-btn">
|
||||||
|
<svg width="18" height="15" viewBox="0 0 18 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.1272 0.939454H12.6584C11.6995 0.939454 10.762 1.21484 9.95532 1.73438L9.0022 2.3457L8.04907 1.73438C7.24323 1.21494 6.30469 0.938941 5.34595 0.939454H0.877197C0.531494 0.939454 0.252197 1.21875 0.252197 1.56445V12.6582C0.252197 13.0039 0.531494 13.2832 0.877197 13.2832H5.34595C6.30493 13.2832 7.24243 13.5586 8.04907 14.0781L8.91626 14.6367C8.94165 14.6523 8.97095 14.6621 9.00024 14.6621C9.02954 14.6621 9.05884 14.6543 9.08423 14.6367L9.95142 14.0781C10.76 13.5586 11.6995 13.2832 12.6584 13.2832H17.1272C17.4729 13.2832 17.7522 13.0039 17.7522 12.6582V1.56445C17.7522 1.21875 17.4729 0.939454 17.1272 0.939454ZM5.34595 11.877H1.65845V2.3457H5.34595C6.03735 2.3457 6.70923 2.54297 7.28931 2.91602L8.24243 3.52734L8.3772 3.61523V12.6387C7.44751 12.1387 6.40845 11.877 5.34595 11.877ZM16.3459 11.877H12.6584C11.5959 11.877 10.5569 12.1387 9.6272 12.6387V3.61523L9.76196 3.52734L10.7151 2.91602C11.2952 2.54297 11.967 2.3457 12.6584 2.3457H16.3459V11.877ZM6.75415 4.8457H3.12524C3.04907 4.8457 2.98657 4.91211 2.98657 4.99219V5.87109C2.98657 5.95117 3.04907 6.01758 3.12524 6.01758H6.7522C6.82837 6.01758 6.89087 5.95117 6.89087 5.87109V4.99219C6.89282 4.91211 6.83032 4.8457 6.75415 4.8457ZM11.1116 4.99219V5.87109C11.1116 5.95117 11.1741 6.01758 11.2502 6.01758H14.8772C14.9534 6.01758 15.0159 5.95117 15.0159 5.87109V4.99219C15.0159 4.91211 14.9534 4.8457 14.8772 4.8457H11.2502C11.1741 4.8457 11.1116 4.91211 11.1116 4.99219ZM6.75415 7.58008H3.12524C3.04907 7.58008 2.98657 7.64648 2.98657 7.72656V8.60547C2.98657 8.68555 3.04907 8.75195 3.12524 8.75195H6.7522C6.82837 8.75195 6.89087 8.68555 6.89087 8.60547V7.72656C6.89282 7.64648 6.83032 7.58008 6.75415 7.58008ZM14.8792 7.58008H11.2502C11.1741 7.58008 11.1116 7.64648 11.1116 7.72656V8.60547C11.1116 8.68555 11.1741 8.75195 11.2502 8.75195H14.8772C14.9534 8.75195 15.0159 8.68555 15.0159 8.60547V7.72656C15.0178 7.64648 14.9553 7.58008 14.8792 7.58008Z" />
|
||||||
|
</svg>
|
||||||
|
<span class="omnivore-top-button-label">Read Now</span>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-open-menu-btn">
|
||||||
|
<svg width="15" height="4" viewBox="0 0 15 4" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<ellipse cx="1.48679" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="7.00217" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="7.00217" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
<ellipse cx="12.5176" cy="1.79492" rx="1.4846" ry="1.5" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-divider"></span>
|
||||||
|
|
||||||
|
<button id="omnivore-toast-close-btn">
|
||||||
|
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="9.50049" cy="9.52783" r="9" />
|
||||||
|
<path d="M12.554 11.874L12.554 11.874L10.2075 9.52783L12.554 7.18165L12.554 7.18164C12.6478 7.08785 12.7005 6.96063 12.7005 6.82798C12.7005 6.69533 12.6478 6.56812 12.554 6.47432C12.4602 6.38053 12.333 6.32783 12.2003 6.32783C12.0677 6.32783 11.9405 6.38053 11.8467 6.47432L11.8467 6.47433L9.50049 8.82087L7.15431 6.47433L7.1543 6.47432C7.0605 6.38053 6.93329 6.32783 6.80064 6.32783C6.66799 6.32783 6.54078 6.38053 6.44698 6.47432C6.35318 6.56812 6.30049 6.69533 6.30049 6.82798C6.30049 6.96063 6.35318 7.08785 6.44698 7.18164L6.44699 7.18165L8.79352 9.52783L6.44699 11.874L6.44698 11.874C6.35318 11.9678 6.30049 12.095 6.30049 12.2277C6.30049 12.3603 6.35318 12.4875 6.44698 12.5813C6.54078 12.6751 6.66799 12.7278 6.80064 12.7278C6.93329 12.7278 7.0605 12.6751 7.1543 12.5813L7.15431 12.5813L9.50049 10.2348L11.8467 12.5813L11.8467 12.5813C11.8931 12.6278 11.9483 12.6646 12.0089 12.6898C12.0696 12.7149 12.1347 12.7278 12.2003 12.7278C12.266 12.7278 12.3311 12.7149 12.3917 12.6898C12.4524 12.6646 12.5076 12.6278 12.554 12.5813C12.6004 12.5349 12.6373 12.4798 12.6624 12.4191C12.6876 12.3584 12.7005 12.2934 12.7005 12.2277C12.7005 12.162 12.6876 12.097 12.6624 12.0363C12.6373 11.9756 12.6004 11.9205 12.554 11.874Z" fill="#EBEBEB" stroke="#EBEBEB" stroke-width="0.4"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-add-note-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-add-note-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<form id="omnivore-add-note-form">
|
||||||
|
<textarea id="omnivore-add-note-textarea" name="title"></textarea>
|
||||||
|
<button class="omnivore-save-button">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="omnivore-edit-title-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-edit-title-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<form id="omnivore-edit-title-form">
|
||||||
|
<textarea id="omnivore-edit-title-textarea" name="title"></textarea>
|
||||||
|
<button class="omnivore-save-button">Save</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="omnivore-edit-labels-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<form id="omnivore-edit-labels-form">
|
||||||
|
<span id="omnivore-edit-labels-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<div id="omnivore-edit-labels-list"></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-extra-buttons-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-extra-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<button id="omnivore-toast-edit-title-btn">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M9.5625 4.50004L13.5 8.43754M6.71406 15.1516L2.84828 11.2858M6.517 15.1875H3.375C3.22582 15.1875 3.08274 15.1283 2.97725 15.0228C2.87176 14.9173 2.8125 14.7742 2.8125 14.625V11.483C2.8125 11.4092 2.82705 11.336 2.85532 11.2678C2.88359 11.1995 2.92502 11.1375 2.97725 11.0853L11.4148 2.64778C11.5202 2.5423 11.6633 2.48303 11.8125 2.48303C11.9617 2.48303 12.1048 2.5423 12.2102 2.64778L15.3523 5.78979C15.4577 5.89528 15.517 6.03835 15.517 6.18754C15.517 6.33672 15.4577 6.4798 15.3523 6.58528L6.91475 15.0228C6.86252 15.075 6.80051 15.1165 6.73226 15.1447C6.66402 15.173 6.59087 15.1875 6.517 15.1875Z" stroke="#6A6968" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
Edit Title
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-menu-divider"></span>
|
||||||
|
<button id="omnivore-toast-archive-btn">
|
||||||
|
<svg width="18" height="16" viewBox="0 0 18 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16.0143 0.166748H1.93155C1.157 0.166748 0.523193 0.800512 0.523193 1.5751V3.92222C0.523193 4.6264 1.03956 5.18958 1.69675 5.30698V14.0148C1.69675 14.7893 2.33052 15.4231 3.10511 15.4231H14.8407C15.6152 15.4231 16.249 14.7894 16.249 14.0148V5.30698C16.9062 5.18959 17.4226 4.6264 17.4226 3.92222V1.5751C17.4226 0.800554 16.7888 0.166748 16.0143 0.166748ZM1.93155 1.5751H16.0143V3.92222H1.93155V1.5751ZM14.8407 14.0148H3.10511V5.33049H14.8407V14.0148Z" fill="#6A6968"/>
|
||||||
|
<path d="M7.82307 8.26431H10.1702C10.5692 8.26431 10.8744 7.95914 10.8744 7.56013C10.8744 7.16114 10.5692 6.85596 10.1702 6.85596H7.82307C7.42408 6.85596 7.1189 7.16113 7.1189 7.56013C7.1189 7.95912 7.44748 8.26431 7.82307 8.26431Z" fill="#6A6968"/>
|
||||||
|
</svg>
|
||||||
|
Archive
|
||||||
|
</button>
|
||||||
|
<span class="omnivore-toast-menu-divider"></span>
|
||||||
|
<button id="omnivore-toast-delete-btn">
|
||||||
|
<svg width="20" height="21" viewBox="0 0 20 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M16.6602 5.16992L3.51147 5.16993" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M8.29272 8.91992V13.9199" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M11.8787 8.91992V13.9199" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M7.09741 2.66992H13.0741" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M15.4648 5.16993V17.0449C15.4648 17.2107 15.4018 17.3697 15.2897 17.4869C15.1777 17.6041 15.0256 17.6699 14.8671 17.6699H5.30445C5.14594 17.6699 4.99392 17.6041 4.88184 17.4869C4.76976 17.3697 4.70679 17.2107 4.70679 17.0449V5.16992" stroke="#6A6968" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="omnivore-logged-out-row" class="omnivore-toast-func-row" data-state="closed">
|
||||||
|
<span id="omnivore-logged-out-status" class="omnivore-toast-func-status"></span>
|
||||||
|
<a href="" id="omnivore-toast-login-btn">Login to Omnivore</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
12
pkg/extension-v3/src/window.d.ts
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
export {}
|
||||||
|
|
||||||
|
declare type AndroidWebKitMessenger = {
|
||||||
|
// 1st argument is an actionID value, 2nd is jsonString
|
||||||
|
handleIdentifiableMessage: (string, string) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
showToolbar?: (payload: { type: string }) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
14
pkg/extension-v3/tsconfig.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./dist",
|
||||||
|
"module": "esnext",
|
||||||
|
"target": "es6",
|
||||||
|
"lib": ["dom", "es6"],
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
39
pkg/extension-v3/webpack.config.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: {
|
||||||
|
background: './src/background.ts',
|
||||||
|
toolbar: './src/scripts/content/toolbar.ts',
|
||||||
|
content: './src/scripts/content/content.ts',
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.ts$/,
|
||||||
|
use: 'ts-loader',
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.ts', '.js'],
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: path.resolve(__dirname, 'extension'),
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CleanWebpackPlugin(),
|
||||||
|
new CopyWebpackPlugin({
|
||||||
|
patterns: [
|
||||||
|
{ from: 'src/manifest.json', to: 'manifest.json' },
|
||||||
|
{ from: 'src/icons', to: 'icons' },
|
||||||
|
{ from: 'src/images', to: 'images' },
|
||||||
|
{ from: 'src/views', to: 'views' },
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}
|
||||||
1467
pkg/extension-v3/yarn.lock
Normal file
@ -95,4 +95,4 @@
|
|||||||
"web_accessible_resources": [
|
"web_accessible_resources": [
|
||||||
"views/toast.html"
|
"views/toast.html"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
- [Docker Compose](#docker-compose)
|
- [Docker Compose](#docker-compose)
|
||||||
- [Nginx Reverse Proxy](#nginx-reverse-proxy)
|
- [Nginx Reverse Proxy](#nginx-reverse-proxy)
|
||||||
- [Cloudflare Tunnel](#cloudflare-tunnel)
|
- [Cloudflare Tunnel](#cloudflare-tunnel)
|
||||||
|
- [Web Extensions](#web-extensions)
|
||||||
- [Email](#email)
|
- [Email](#email)
|
||||||
- - [IMap Watcher](#imap-watcher)
|
- - [IMap Watcher](#imap-watcher)
|
||||||
- - [Self Hosted Mail Server](#docker-mailserver-and-mail-watcher)
|
- - [Self Hosted Mail Server](#docker-mailserver-and-mail-watcher)
|
||||||
@ -136,6 +137,40 @@ Omnivore is no way affiliated with Cloudflare, it is just the method to which th
|
|||||||
|
|
||||||
[Read More](https://www.cloudflare.com/products/tunnel/)
|
[Read More](https://www.cloudflare.com/products/tunnel/)
|
||||||
|
|
||||||
|
## Web Extensions
|
||||||
|
The web extensions have been updated to support self-hosting - The manifest version 2 of these could be enabled to work with Self-hosting, but required some manual code changes.
|
||||||
|
|
||||||
|
The extension has been updated for Manifest v3, and to hopefully ease the difficulty of making it work with Self-Hosted versions.
|
||||||
|
|
||||||
|
These extensions have been sent for submission to the Chrome and Firefox webstore, but are awaiting approval. In the mean-time, a guide about how to install these manually is provided.
|
||||||
|
|
||||||
|
### Chrome
|
||||||
|
|
||||||
|
1. Navigate to the Chrome extension page at Chrome://extensions
|
||||||
|

|
||||||
|
|
||||||
|
2. Enable Developer mode on the Extensions page using the toggle.
|
||||||
|

|
||||||
|
3. Use the Load Unpacked Option to load the extension from source.
|
||||||
|

|
||||||
|
4. Navigate to the source folder, found at pkg/extension-v3/extension
|
||||||
|

|
||||||
|

|
||||||
|
5. The extension should have been installed. Go to the details page on the newly installed extension
|
||||||
|

|
||||||
|
6. Navigate to the options page, using the "Extensions Options" button. You should see the following page.
|
||||||
|

|
||||||
|

|
||||||
|
7. Generate an API Key using Omnivore.
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
8. Update the settings with the hosted options
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Emails and Newsletters
|
## Emails and Newsletters
|
||||||
|
|
||||||
|
|||||||