Emoji favicons for the web
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

enable reload on favicon update

+115 -59
+29 -14
source/background.ts
··· 2 2 * Serves as bridge point between popup and content_script. 3 3 */ 4 4 5 - import type { Settings } from './types.ts'; 5 + import type { Favicon, Settings } from './types.ts'; 6 6 import type { 7 7 Tab, 8 8 TabChangeInfo, ··· 17 17 18 18 await updateCache() 19 19 20 + function selectFavicon(url: string | void, settings: Settings): [Favicon | void, boolean] { 21 + const { ignoreList = [], siteList = [], features = {} } = settings; 22 + 23 + if (url) { 24 + const listItemMatchesUrl = (site: string) => (new RegExp(site)).test(url); 25 + 26 + if ( 27 + features.enableSiteIgnore && 28 + ignoreList.some(listItemMatchesUrl) 29 + ) { 30 + return [undefined, false]; 31 + } 32 + 33 + const shouldOverride = siteList.some(listItemMatchesUrl); 34 + 35 + if (shouldOverride) { 36 + return [{ id: 'smile', emoji: '😀' }, shouldOverride]; 37 + } else if (features.enableFaviconAutofill) { 38 + const { host } = new URL(url); 39 + return [autoselector.selectFavicon(host), shouldOverride]; 40 + } 41 + } 42 + 43 + return [undefined, false]; 44 + } 45 + 20 46 browserAPI.storage.onChanged.addListener(async () => { 21 47 await updateCache(); 22 48 }); 23 49 24 50 browserAPI.tabs.onUpdated.addListener( 25 51 (tabId: number, _: TabChangeInfo, tab: Tab) => { 26 - const { siteList = [], features = {} } = settings; 27 - 28 - if (!tab.url) return; 29 - 30 - const shouldOverride = (siteList || []).some( 31 - (site: string) => (new RegExp(site)).test(tab.url || ''), 32 - ); 33 - 34 - if (shouldOverride) { 35 - const favicon = { id: 'smile', emoji: '😀' }; 36 - browserAPI.tabs.sendMessage(tabId, { favicon, shouldOverride: true }); 37 - } else if (features.enableFaviconAutofill) { 38 - const favicon = autoselector.selectFavicon(new URL(tab.url).host); 52 + const [favicon, shouldOverride] = selectFavicon(tab.url, settings) || []; 53 + if (favicon) { 39 54 browserAPI.tabs.sendMessage(tabId, { favicon, shouldOverride }); 40 55 } 41 56 },
+8 -1
source/content_script.ts
··· 5 5 * Use those to determine if we should override favicon 6 6 * Override favicon if applicable 7 7 */ 8 - import type { Favicon } from './utilities/database.ts'; 8 + import type { Favicon } from './types.ts'; 9 9 import { appendFaviconLink } from './utilities/favicon_helpers.ts'; 10 10 import browserAPI from './utilities/browser_api.ts'; 11 11 ··· 15 15 const newDiff = newValue.filter(includesCurrUrl); 16 16 const oldDiff = oldValue.filter(includesCurrUrl); 17 17 if (newDiff.length !== oldDiff.length) location.reload(); 18 + } else if (changes?.ignoreList) { 19 + const { newValue = [], oldValue = [] } = changes?.ignoreList || {}; 20 + const newDiff = newValue.filter(includesCurrUrl); 21 + const oldDiff = oldValue.filter(includesCurrUrl); 22 + if (newDiff.length !== oldDiff.length) location.reload(); 23 + } else if (changes?.features?.newValue?.enableSiteIgnore != null) { 24 + location.reload(); 18 25 } 19 26 }); 20 27
+4
source/hooks/use_browser_storage.ts
··· 36 36 setCache(storage as Type); 37 37 setLoading(false); 38 38 }); 39 + 40 + browserAPI.storage.onChanged.addListener(async (changes) => { 41 + setCache(await storage.sync.get(keys) as Type); 42 + }); 39 43 }, []); 40 44 41 45 const saveToStorage = useCallback(
+3 -1
source/hooks/use_list_state.ts
··· 1 - import { useCallback, useState } from 'preact/hooks'; 1 + import { useCallback, useEffect, useState } from 'preact/hooks'; 2 2 3 3 // deno-lint-ignore no-explicit-any 4 4 type ListItem = any; ··· 12 12 13 13 export default (initialValue: ListItem[]) => { 14 14 const [contents, setContents] = useState(initialValue); 15 + 16 + useEffect(() => setContents(initialValue) , [ initialValue ]); 15 17 16 18 return { 17 19 contents,
+17 -9
source/popup.tsx
··· 17 17 const { favIconUrl = '', url = '' } = currTab || {}; 18 18 19 19 useEffect(() => { 20 - browserAPI.tabs.query(queryOptions) 21 - .then(([tab]: Tab[]) => setCurrTab(tab)); 20 + async function setup() { 21 + const [ activeTab ] = await browserAPI.tabs.query(queryOptions); 22 + setCurrTab(activeTab); 23 + } 24 + browserAPI.storage.onChanged.addListener(setup); 25 + browserAPI.tabs.onUpdated.addListener(setup); 22 26 23 - browserAPI.storage.onChanged.addListener(async () => { 24 - const [ tab ] = await browserAPI.tabs.query(queryOptions) 25 - setCurrTab(tab); 26 - }); 27 + setup().catch(console.error); 27 28 }, [cache]); 28 29 29 30 const { status, save } = useStatus( ··· 53 54 if (loading) return <div>loading...</div> 54 55 55 56 return ( 56 - <div className='page'> 57 - <h1>Favioli</h1> 58 - <p>Current Favicon: {favIconUrl ? <img className="favicon-icon" src={favIconUrl} width={20} height={20} /> : null}</p> 57 + <div className='popup-wrapper'> 58 + <p> 59 + Current Favicon: 60 + <img 61 + className="favicon-icon" 62 + src={favIconUrl} 63 + width={20} 64 + height={20} 65 + /> 66 + </p> 59 67 <button onClick={addToOverrides}> 60 68 Override Favicon 61 69 </button>
+12
source/static/styles/options.css
··· 1 + /** RESET **/ 2 + html, body { 3 + margin: 0; 4 + padding: 0; 5 + line-height: 1.6; 6 + font-size: 24px; 7 + font-weight: 400; 8 + font-family: BlinkMacSystemFont, Avenir, "Avenir Next", "Roboto", "Ubuntu", "Helvetica Neue", sans-serif; 9 + color: var(--text-color); 10 + background: var(--background-color); 11 + } 12 + 1 13 html { 2 14 font-size: 24px; 3 15 min-width: 600px;
+21
source/static/styles/popup.css
··· 1 + /** RESET **/ 2 + html, body { 3 + margin: 0; 4 + padding: 0; 5 + line-height: 1.6; 6 + font-family: BlinkMacSystemFont, Avenir, "Avenir Next", "Roboto", "Ubuntu", "Helvetica Neue", sans-serif; 7 + color: var(--text-color); 8 + background: var(--background-color); 9 + } 10 + 1 11 .favicon-icon { 2 12 vertical-align: middle; 3 13 padding-left: 5px; 4 14 } 15 + 16 + .popup-wrapper { 17 + width: 300px; 18 + display: flex; 19 + flex-flow: column; 20 + } 21 + 22 + button { 23 + padding: 5px; 24 + margin: 5px; 25 + }
-11
source/static/styles/shared.css
··· 1 - /** RESET **/ 2 - html, body { 3 - margin: 0; 4 - padding: 0; 5 - line-height: 1.6; 6 - font-size: 24px; 7 - font-weight: 400; 8 - font-family: BlinkMacSystemFont, Avenir, "Avenir Next", "Roboto", "Ubuntu", "Helvetica Neue", sans-serif; 9 - color: var(--text-color); 10 - background: var(--background-color); 11 - }
+20 -2
source/types.ts
··· 1 - type Favicon = string; 2 1 type IgnoreItem = string; 3 - type UrlFaviconPair = [string, Favicon]; 4 2 5 3 export interface Settings { 6 4 siteList: IgnoreItem[]; ··· 10 8 enableFaviconAutofill?: boolean; 11 9 enableSiteIgnore?: boolean; 12 10 }; 11 + } 12 + 13 + /** 14 + * Local Icon Database 15 + * Used to store favicons for later usage. 16 + */ 17 + export interface Favicon { 18 + id: string; // ID representing favicon (nickname, etc) 19 + video?: string; // Priority 1: Optional multiframe favicon 20 + image?: string; // Priority 2: Optional singleframe favicon 21 + emoji?: string; // Priority 3: Optional emoji favicon 22 + } 23 + 24 + /** 25 + * Video, Image, Emoji are all pointers to source 26 + * This is so we can point multiple ids to the same data 27 + */ 28 + export interface Source { 29 + id: string; // Generated by DB 30 + data: string; // emoji string or base64 image 13 31 } 14 32 15 33 export const defaultSettings: Settings = {
+1 -1
source/utilities/autoselector.ts
··· 1 - import type { Favicon } from './database.ts'; 1 + import type { Favicon } from '../types.ts'; 2 2 3 3 import * as emoji from 'https://deno.land/x/emoji/mod.ts'; 4 4 import LEGACY_EMOJI_SET from '../config/legacy_autoselect_set.ts';
-20
source/utilities/database.ts
··· 1 - /** 2 - * Local Icon Database 3 - * Used to store favicons for later usage. 4 - */ 5 - 6 - export interface Favicon { 7 - id: string; // ID representing favicon (nickname, etc) 8 - video?: string; // Priority 1: Optional multiframe favicon 9 - image?: string; // Priority 2: Optional singleframe favicon 10 - emoji?: string; // Priority 3: Optional emoji favicon 11 - } 12 - 13 - /** 14 - * Video, Image, Emoji are all pointers to source 15 - * This is so we can point multiple ids to the same data 16 - */ 17 - export interface Source { 18 - id: string; // Generated by DB 19 - data: string; // emoji string or base64 image 20 - }