Fix: New favicon notification badge to fix rendering issues (#210)

This commit is contained in:
Ralph Slooten
2023-12-04 21:24:46 +13:00
parent 3a35ded5bf
commit 5365313f9a
5 changed files with 128 additions and 26 deletions

6
package-lock.json generated
View File

@@ -17,7 +17,6 @@
"moment": "^2.29.4",
"prismjs": "^1.29.0",
"rapidoc": "^9.3.4",
"tinycon": "^0.6.8",
"vue": "^3.2.13",
"vue-css-donut-chart": "^2.0.0",
"vue-router": "^4.2.4"
@@ -2409,11 +2408,6 @@
"node": ">=6"
}
},
"node_modules/tinycon": {
"version": "0.6.8",
"resolved": "https://registry.npmjs.org/tinycon/-/tinycon-0.6.8.tgz",
"integrity": "sha512-bF8Lxm4JUXF6Cw0XlZdugJ44GV575OinZ0Pt8vQPr8ooNqd2yyNkoFdCHzmdpHlgoqfSLfcyk4HDP1EyllT+ug=="
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",

View File

@@ -18,7 +18,6 @@
"moment": "^2.29.4",
"prismjs": "^1.29.0",
"rapidoc": "^9.3.4",
"tinycon": "^0.6.8",
"vue": "^3.2.13",
"vue-css-donut-chart": "^2.0.0",
"vue-router": "^4.2.4"

View File

@@ -1,5 +1,6 @@
<script>
import CommonMixins from './mixins/CommonMixins'
import Favicon from './components/Favicon.vue'
import Notifications from './components/Notifications.vue'
import { RouterView } from 'vue-router'
import { mailbox } from "./stores/mailbox"
@@ -8,6 +9,7 @@ export default {
mixins: [CommonMixins],
components: {
Favicon,
Notifications,
},
@@ -33,5 +35,6 @@ export default {
<template>
<RouterView />
<Favicon />
<Notifications />
</template>

View File

@@ -0,0 +1,125 @@
<script>
import { mailbox } from '../stores/mailbox.js'
export default {
data() {
return {
favicon: false,
iconPath: false,
iconTextColor: '#ffffff',
iconBgColor: '#dd0000',
iconFontSize: 40,
iconProcessing: false,
iconTimeout: 500,
}
},
mounted() {
this.favicon = document.head.querySelector('link[rel="icon"]')
if (this.favicon) {
this.iconPath = this.favicon.href
}
},
computed: {
count() {
let i = mailbox.unread
if (i > 1000) {
i = Math.floor(i / 1000) + 'k'
}
return i
}
},
watch: {
count() {
if (!this.favicon || this.iconProcessing) {
return
}
this.iconProcessing = true
let self = this
window.setTimeout(() => {
self.icoUpdate()
}, this.iconTimeout)
},
},
methods: {
async icoUpdate() {
if (!this.favicon) {
return
}
if (!this.count) {
this.iconProcessing = false
this.favicon.href = this.iconPath
return
}
let fontSize = this.iconFontSize
// Draw badge text
let textPaddingX = 7
let textPaddingY = 3
let strlen = this.count.toString().length
if (strlen > 2) {
// if text >= 3 characters then reduce size and padding
textPaddingX = 4
fontSize = strlen > 3 ? 30 : 36
}
console.log(fontSize)
let canvas = document.createElement('canvas')
canvas.width = 64
canvas.height = 64
let ctx = canvas.getContext('2d')
// Draw base icon
let icon = new Image()
icon.src = this.iconPath
await icon.decode()
ctx.drawImage(icon, 0, 0, 64, 64)
// Measure text
ctx.font = `${fontSize}px Arial, sans-serif`
ctx.textAlign = 'right'
ctx.textBaseline = 'top'
let textMetrics = ctx.measureText(this.count)
// Draw badge
let paddingX = 7
let paddingY = 4
let cornerRadius = 8
let width = textMetrics.width + paddingX * 2
let height = fontSize + paddingY * 2
let x = canvas.width - width
let y = canvas.height - height - 1
ctx.fillStyle = this.iconBgColor
ctx.roundRect(x, y, width, height, cornerRadius)
ctx.fill()
ctx.fillStyle = this.iconTextColor
ctx.fillText(
this.count,
canvas.width - textPaddingX,
canvas.height - fontSize - textPaddingY
)
this.iconProcessing = false
this.favicon.href = canvas.toDataURL("image/png")
}
}
}
</script>
<template></template>

View File

@@ -1,14 +1,6 @@
// State Management
import { reactive, watch } from 'vue'
import Tinycon from 'tinycon'
Tinycon.setOptions({
height: 11,
background: '#dd0000',
fallback: false,
font: '9px arial, sans-serif',
})
// global mailbox info
export const mailbox = reactive({
@@ -29,17 +21,6 @@ export const mailbox = reactive({
lastMessage: false, // return scrolling
})
watch(
() => mailbox.unread,
(v) => {
if (v == 0) {
Tinycon.reset()
} else {
Tinycon.setBubble(v)
}
}
)
watch(
() => mailbox.count,
(v) => {