-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Option to choose different emojis for each Pomodoro (#15)
- Loading branch information
Showing
10 changed files
with
321 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
/** | ||
* Build the `lib/emoji-svg.js` JavaScript from SVG files in the `noto-emoji` Git repo. | ||
* | ||
* © NDF, 07-Sep-2024. | ||
* @see https://github.com/googlefonts/noto-emoji | ||
*/ | ||
|
||
const fs = require('fs').promises; | ||
const { resolve } = require('path'); | ||
const { EMOJI } = require('../lib/Icons.js'); | ||
|
||
const outputJsPath = resolve(__dirname, '..', 'lib', 'emoji-svg.js'); | ||
|
||
const SVG = EMOJI.map(async (it, idx) => { | ||
const xml = await fs.readFile(svgFilePath(it.codepoint), 'utf8'); | ||
|
||
const svg = trimSvgXml(xml); | ||
|
||
return { id: it.code, svg }; | ||
}); | ||
|
||
console.log('SVG emoji count:', SVG.length); | ||
|
||
Promise.all(SVG).then((svgData) => { | ||
const svgJson = JSON.stringify(svgData, null, 2); | ||
|
||
return fs.writeFile(outputJsPath, jsFileTemplate(svgJson)); | ||
}) | ||
.then(() => console.log('File emoji-svg.js written OK.')); | ||
|
||
/* | ||
Utility functions. | ||
*/ | ||
|
||
function trimSvgXml (xml) { | ||
return xml.replace(/<\?xml[^>]+\?>\n/, '').replace(/<!--[^>]+-->\n/, '') | ||
.replace(' xmlns:xlink="http://www.w3.org/1999/xlink"', '') | ||
.replace(/ version="\d.\d"/, '').replace(/ id="Layer_\d"/, '') | ||
.replace(/\t/g, '').replace(/\n/g, ''); | ||
} | ||
|
||
function codePoint (codepoint) { | ||
return codepoint.replace('U+', '').toLowerCase(); | ||
} | ||
|
||
function svgFileName (codepoint) { | ||
return `emoji_u${codePoint(codepoint)}.svg`; | ||
} | ||
|
||
function svgFilePath (codepoint) { | ||
return resolve(__dirname, '..', 'noto-emoji', 'svg', svgFileName(codepoint)); | ||
} | ||
|
||
function jsFileTemplate (jsonSvgData) { | ||
return `/* Auto-generated. */ | ||
/* eslint-disable quotes, quote-props */ | ||
export const SVG = ${jsonSvgData}; | ||
export default SVG; | ||
/* eslint-enable */ | ||
`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
/** | ||
* | ||
* @see https://codepen.io/nfreear/pen/abgRwdY | ||
* @see https://emojipedia.org/evergreen-tree#technical | ||
*/ | ||
|
||
const emojiSvgJs = './emoji-svg.js'; | ||
|
||
export const EMOJI = [ | ||
{ | ||
name: 'Tree', | ||
phrase: 'Grow a tree!', | ||
emoji: '🌲', | ||
code: 'evergreen_tree', // Shortcode: `:evergreen_tree:` | ||
codepoint: 'U+1F332' | ||
}, { | ||
name: 'Bean', | ||
phrase: 'Collect a bean!', | ||
emoji: '🫘', | ||
code: 'beans', | ||
codepoint: 'U+1FAD8' | ||
}, { | ||
name: 'Chocolate', | ||
phrase: 'Eat chocolate!', | ||
emoji: '🍫', | ||
code: 'chocolate_bar', | ||
codepoint: 'U+1F36B' | ||
}, { | ||
name: 'Hot drink', | ||
phrase: 'Have a hot drink!', | ||
emoji: '☕', | ||
code: 'hot_beverage', | ||
codepoint: 'U+2615' | ||
}, /* { | ||
name: 'Yarn', | ||
phrase: 'Do crafts!', | ||
emoji: '🧶', | ||
code: 'yarn', | ||
codepoint: 'U+1F9F6' | ||
}, */ { | ||
name: 'Star', | ||
phrase: 'Collect a star!', | ||
emoji: '⭐', | ||
code: 'star', | ||
codepoint: 'U+2B50' | ||
}, { | ||
name: 'Walking', | ||
phrase: 'Take a break!', | ||
emoji: '🚶', | ||
code: 'person_walking', | ||
codepoint: 'U+1F6B6' | ||
} | ||
]; | ||
|
||
const APP_ICONS = [ | ||
{ | ||
name: 'Cog', // Settings/ Options. | ||
emoji: '⚙️', | ||
code: 'gear' | ||
}, { | ||
name: 'Timer', | ||
emoji: '⏱️', | ||
code: 'stopwatch', | ||
codepoint: 'U+23F1 U+FE0F' | ||
} | ||
]; | ||
|
||
export class Icons { | ||
get emoji () { return EMOJI; } | ||
get appIcons () { return APP_ICONS; } | ||
|
||
get default () { return this.find('evergreen_tree'); } | ||
get cog () { return this.findAppIcon('gear'); } | ||
get timer () { return this.findAppIcon('stopwatch'); } | ||
|
||
getSelectOptions () { | ||
return this.emoji.map((it) => { | ||
const { code, emoji, name } = it; | ||
return `<option value="${code}" data-emoji="${emoji}">${emoji} ${name}</option>`; | ||
}); | ||
} | ||
|
||
find (byCode) { | ||
return this.emoji.find((it) => it.code === byCode); | ||
} | ||
|
||
findAppIcon (byCode) { | ||
return this.appIcons.find(it => it.code === byCode); | ||
} | ||
|
||
findEmojiSVG (byId) { | ||
const found = this._SVG.find(it => it.id === byId); | ||
if (!found) { | ||
// throw new Error(`SVG emoji not found: "${byId}"`); | ||
console.error(`Error: SVG emoji not found: "${byId}"`); | ||
return `<div class="error">Error: SVG emoji not found: "<tt>${byId}</tt>"</div>`; | ||
} | ||
const { name } = this.find(byId); | ||
return `<span role="img" aria-label="${name}"> | ||
<span class="emoji-svg" aria-hidden="true" data-emoji-id="${byId}"> | ||
${found.svg} | ||
</span> | ||
</span>`; | ||
} | ||
|
||
async importEmojiSVG () { | ||
const { default: SVG } = await import(emojiSvgJs); | ||
this._SVG = SVG; | ||
console.debug('SVG:', SVG); | ||
return SVG; | ||
} | ||
} | ||
|
||
export default Icons; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,17 +9,17 @@ | |
* @copright © Nick Freear and contributors, 01-August-2024. | ||
*/ | ||
|
||
const CSP = "script-src 'self'; img-src chrome-extension: 'self'; font-src 'self' https://fonts.gstatic.com/; upgrade-insecure-requests;"; | ||
|
||
class CSDialogTimer { | ||
get _template () { | ||
return ` | ||
<template> | ||
<link href="${this._stylesheet}" rel="stylesheet"> | ||
<!-- <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:[email protected]" rel="stylesheet"> --> | ||
<dialog part="dialog"> | ||
<h1 part="hdg"> My Pomodoro </h1> | ||
<p> | ||
<img alt="evergreen tree" src="${this.getURL('/assets/evergreen_tree.svg')}"> | ||
<!-- <i class="material-symbols-outlined tree-icon">park</i> --> | ||
<p class="emoji-svg"> | ||
<x-svg> Loading emoji … </x-svg> | ||
</p> | ||
<p> | ||
<output id="my-timer" part="output"> </output> | ||
|
@@ -45,10 +45,14 @@ class CSDialogTimer { | |
return this.getURL('/assets/content-style.css'); | ||
} | ||
|
||
createShowElement () { | ||
async createShowElement () { | ||
await this.importEmojiSVG(); | ||
|
||
const ELEM = this._element = document.createElement('my-pomodoro-timer'); | ||
|
||
this._attachLocalTemplate(ELEM, this._template); | ||
const TEMPLATE = this.replaceWithEmojiSVG(); | ||
|
||
this._attachLocalTemplate(ELEM, TEMPLATE); | ||
|
||
document.body.appendChild(ELEM); | ||
|
||
|
@@ -137,14 +141,52 @@ class CSDialogTimer { | |
elem.appendChild(docFragment); | ||
} | ||
} | ||
|
||
addCSP () { | ||
const META = document.createElement('meta'); | ||
META.setAttribute('http-equiv', 'Content-Security-Policy'); | ||
META.setAttribute('content', CSP); | ||
document.head.appendChild(META); | ||
} | ||
|
||
/* addSVGCallback (callbackFunc) { | ||
this._svgFunc = callbackFunc; | ||
} */ | ||
|
||
findEmojiSVG (byId) { | ||
return this._icons.findEmojiSVG(byId); | ||
} | ||
|
||
replaceWithEmojiSVG () { | ||
return this._template.replace('<x-svg></x-svg>', this.findEmojiSVG('beans')); | ||
} | ||
|
||
/* | ||
https://stackoverflow.com/questions/48104433/how-to-import-es6-modules-in-content-script-for-chrome-extension | ||
*/ | ||
async importEmojiSVG () { | ||
const src = this.getURL('lib/Icons.js'); | ||
const { Icons } = await import(src); | ||
this._icons = new Icons(); | ||
await this._icons.importEmojiSVG(); | ||
} | ||
} | ||
|
||
/* (async () => { | ||
const src = chrome.runtime.getURL('lib/emoji-svg.js'); | ||
const contentMain = await import(src); | ||
// contentMain.main(); | ||
})(); */ | ||
|
||
const dialogTimer = new CSDialogTimer(); | ||
|
||
dialogTimer.createShowElement(); | ||
dialogTimer.handleUserEvents(); | ||
// dialogTimer.addStylesheet(); | ||
// dialogTimer.getStatus(); | ||
dialogTimer.listen(); | ||
dialogTimer.createShowElement().then(() => { | ||
dialogTimer.handleUserEvents(); | ||
// dialogTimer.addStylesheet(); | ||
// dialogTimer.getStatus(); | ||
dialogTimer.listen(); | ||
}); | ||
|
||
// dialogTimer.addCSP(); | ||
|
||
console.debug('>> content-script.js'); |
Oops, something went wrong.