Skip to content

Commit

Permalink
feat(inbox): add favicon to inbox
Browse files Browse the repository at this point in the history
  • Loading branch information
thesophiaxu committed Jan 14, 2022
1 parent f69e71d commit 973b3f3
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const AutoDynamicViewDetailed: DynamicViewRenderer = ({
context,
component,
attributes,
onLoad,
useFallback = true,
}) => {
const isObjectStub = isStub(object);
Expand Down Expand Up @@ -41,6 +42,7 @@ export const AutoDynamicViewDetailed: DynamicViewRenderer = ({
query,
(objects: any[]) => {
setLoadedObj(objects[0]);
if (typeof onLoad === 'function') onLoad(objects[0]);
},
newSubs,
{ noExpand: true },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import _ from 'lodash';
import React from 'react';
import { Badger } from '../../utils';
import { AutoDynamicViewDetailed } from '../ObjectView/AutoDynamicViewDetailed';

export function Inbox() {
const [onUpdate, setOnUpdate] = React.useState(_.noop);

React.useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);
const pn = urlParams.get('pageName');
if (pn === 'inbox') {
const myBadge = new Badger({});
setOnUpdate(() => (data: any) => {
const badgeCount = data?._value?.children?.['_value[']?.length || undefined;
console.log(badgeCount);
myBadge.value = badgeCount;
});
}
}, []);

return (
<AutoDynamicViewDetailed
object={{
Expand All @@ -9,6 +27,7 @@ export function Inbox() {
type: { 'unigraph.id': '$/schema/list' },
}}
attributes={{ removeOnEnter: true }}
onLoad={onUpdate}
/>
);
}
156 changes: 156 additions & 0 deletions packages/unigraph-dev-explorer/src/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable class-methods-use-this */
/* eslint-disable @typescript-eslint/no-empty-function */
/* eslint-disable no-bitwise */
/* eslint-disable no-plusplus */
Expand Down Expand Up @@ -322,3 +323,158 @@ export const runClientExecutable = (src: string, params: any) => {
).bind(this, require, unpad, { params }, window.unigraph);
fn();
};

/**
* Add notification badge (pill) to favicon in browser tab
* @url stackoverflow.com/questions/65719387/
*/
export class Badger {
canvas: HTMLCanvasElement;

src: any;

ctx: any;

radius: any;

offset: any;

badgeSize: any;

backgroundColor: any;

color: any;

size: any;

position: any;

_value!: number;

onChange: any;

img!: HTMLImageElement;

faviconSize!: number;

constructor(options: any) {
Object.assign(
this,
{
backgroundColor: '#0cf',
color: '#fff',
size: 1, // 0..1 (Scale in respect to the favicon image size)
position: 'c', // Position inside favicon "n", "e", "s", "w", "ne", "nw", "se", "sw"
radius: 16, // Border radius
src: '', // Favicon source (dafaults to the <link> icon href)
onChange() {},
},
options,
);
this.canvas = document.createElement('canvas');
this.src = this.src || this.faviconEL?.getAttribute('href');
this.ctx = this.canvas.getContext('2d');
}

faviconEL = document.querySelector('link[rel$=icon]');

_drawIcon() {
this.ctx.clearRect(0, 0, this.faviconSize, this.faviconSize);
this.ctx.drawImage(this.img, 0, 0, this.faviconSize, this.faviconSize);
}

_drawShape() {
const r = this.radius;
const xa = this.offset.x;
const ya = this.offset.y;
const xb = this.offset.x + this.badgeSize;
const yb = this.offset.y + this.badgeSize;
this.ctx.beginPath();
this.ctx.moveTo(xb - r, ya);
this.ctx.quadraticCurveTo(xb, ya, xb, ya + r);
this.ctx.lineTo(xb, yb - r);
this.ctx.quadraticCurveTo(xb, yb, xb - r, yb);
this.ctx.lineTo(xa + r, yb);
this.ctx.quadraticCurveTo(xa, yb, xa, yb - r);
this.ctx.lineTo(xa, ya + r);
this.ctx.quadraticCurveTo(xa, ya, xa + r, ya);
this.ctx.fillStyle = this.backgroundColor;
this.ctx.fill();
this.ctx.closePath();
}

_drawVal() {
const margin = (this.badgeSize * 0.18) / 2;
this.ctx.beginPath();
this.ctx.textBaseline = 'middle';
this.ctx.textAlign = 'center';
this.ctx.font = `bold ${this.badgeSize * 0.6}px Arial`;
this.ctx.fillStyle = this.color;
this.ctx.fillText(this.value, this.badgeSize / 2 + this.offset.x, this.badgeSize / 2 + this.offset.y + margin);
this.ctx.closePath();
}

_drawFavicon() {
this.faviconEL!.setAttribute('href', this.dataURL);
}

_draw() {
this._drawIcon();
if (this.value) this._drawShape();
if (this.value) this._drawVal();
this._drawFavicon();
}

_setup() {
this.faviconSize = this.img.naturalWidth;
this.badgeSize = this.faviconSize * this.size;
this.canvas.width = this.faviconSize;
this.canvas.height = this.faviconSize;
const sd = this.faviconSize - this.badgeSize;
const sd2 = sd / 2;
this.offset = (
{
n: { x: sd2, y: 0 },
e: { x: sd, y: sd2 },
s: { x: sd2, y: sd },
w: { x: 0, y: sd2 },
nw: { x: 0, y: 0 },
ne: { x: sd, y: 0 },
sw: { x: 0, y: sd },
se: { x: sd, y: sd },
c: { x: sd2, y: sd2 },
} as any
)[this.position];
}

// Public functions / methods:

update() {
this._value = Math.min(999, parseInt(this._value as any, 10));
if (this.img) {
this._draw();
if (this.onChange) this.onChange.call(this);
} else {
this.img = new Image();
this.img.addEventListener('load', () => {
this._setup();
this._draw();
if (this.onChange) this.onChange.call(this);
});
this.img.src = this.src;
}
}

get dataURL() {
return this.canvas.toDataURL();
}

get value() {
return this._value;
}

set value(val) {
this._value = val;
this.update();
}
}

0 comments on commit 973b3f3

Please sign in to comment.