Skip to content

Commit

Permalink
feat: Option to choose different emojis for each Pomodoro (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
nfreear committed Sep 8, 2024
1 parent bbdef2a commit c21c4b8
Show file tree
Hide file tree
Showing 10 changed files with 321 additions and 15 deletions.
10 changes: 10 additions & 0 deletions assets/content-style.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,13 @@ img[ src *= evergreen_tree ] {
font-size: 5rem;
font-variation-settings: 'FILL' 1;
}

.emoji {
font-family: "Noto Color Emoji", emoji;
font-size: 5rem;
}

.emoji-svg svg {
height: 8rem;
width: 8rem;
}
14 changes: 14 additions & 0 deletions assets/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,17 @@ img[ src *= evergreen_tree ] {
font-size: 5rem;
font-variation-settings: 'FILL' 1;
}

.emoji {
font-family: "Noto Color Emoji", emoji;
font-size: 5rem;
}

.emoji-svg svg {
height: 8rem;
width: 8rem;
}

.error {
color: darkred;
}
65 changes: 65 additions & 0 deletions build/emoji-svg-js.js
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 */
`;
}
10 changes: 9 additions & 1 deletion build/manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const IS_GECKO = process.env.UA === 'gecko';

const FILE_PATH = resolve(__dirname, '..', 'manifest.json');
const SERVICE_WORKER = 'lib/service-worker.js';
// const BACKGROUND_PAGE = 'pages/background.html';

const TEMPLATE = {
manifest_version: 3,
Expand Down Expand Up @@ -41,6 +42,8 @@ const TEMPLATE = {
'http://*/*'
],

// content_security_policy: "script-src 'self'; font-src 'self' https://fonts.gstatic.com/; upgrade-insecure-requests;",

background: {
// scripts: ['lib/service-worker.js'],
// service_worker: 'lib/service-worker.js'
Expand All @@ -64,7 +67,10 @@ const TEMPLATE = {
matches: ['https://*/*'],
resources: [
'assets/content-style.css',
'assets/evergreen_tree.svg'
// 'assets/evergreen_tree.svg',
// 'assets/emoji.svg',
'lib/emoji-svg.js',
'lib/Icons.js'
]
}
]
Expand All @@ -82,10 +88,12 @@ const GECKO = {
const MANIFEST = IS_GECKO ? { ...TEMPLATE, ...GECKO } : TEMPLATE;

if (IS_GECKO) {
// MANIFEST.background.page = BACKGROUND_PAGE;
MANIFEST.background.scripts = [SERVICE_WORKER];
} else {
// Chromium-specific.
MANIFEST.background.service_worker = SERVICE_WORKER;
MANIFEST.background.type = 'module';

MANIFEST.permissions.push('offscreen');
}
Expand Down
114 changes: 114 additions & 0 deletions lib/Icons.js
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;
64 changes: 53 additions & 11 deletions lib/content-script.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 &hellip; </x-svg>
</p>
<p>
<output id="my-timer" part="output">&nbsp;</output>
Expand All @@ -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);

Expand Down Expand Up @@ -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');
Loading

0 comments on commit c21c4b8

Please sign in to comment.