commit: d905a6cb7047a40117714639b7b4578e0ab5f7a9
parent fa2884a8052bfe4f4d9d069ff9d1d15765c3bba8
Author: Shpuld Shpludson <shp@cock.li>
Date: Tue, 17 Nov 2020 18:25:05 +0000
Merge branch 'feat/favicon-badge' into 'develop'
Add favicon badge for unread notifs
See merge request pleroma/pleroma-fe!1273
Diffstat:
4 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
@@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Import/export a muted users
- Proper handling of deletes when using websocket streaming
- Added optimistic chat message sending, so you can start writing next message before the previous one has been sent
+- Added a small red badge to the favicon when there's unread notifications
### Fixed
- Fixed clicking NSFW hider through status popover
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
@@ -7,6 +7,7 @@ import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
import { applyTheme } from '../services/style_setter/style_setter.js'
+import FaviconService from '../services/favicon_service/favicon_service.js'
let staticInitialResults = null
@@ -326,6 +327,8 @@ const afterStoreSetup = async ({ store, i18n }) => {
const width = windowWidth()
store.dispatch('setMobileLayout', width <= 800)
+ FaviconService.initFaviconService()
+
const overrides = window.___pleromafe_dev_overrides || {}
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
store.dispatch('setInstanceOption', { name: 'server', value: server })
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
@@ -6,6 +6,7 @@ import {
filteredNotificationsFromStore,
unseenNotificationsFromStore
} from '../../services/notification_utils/notification_utils.js'
+import FaviconService from '../../services/favicon_service/favicon_service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
@@ -75,8 +76,10 @@ const Notifications = {
watch: {
unseenCountTitle (count) {
if (count > 0) {
+ FaviconService.drawFaviconBadge()
this.$store.dispatch('setPageTitle', `(${count})`)
} else {
+ FaviconService.clearFaviconBadge()
this.$store.dispatch('setPageTitle', '')
}
}
diff --git a/src/services/favicon_service/favicon_service.js b/src/services/favicon_service/favicon_service.js
@@ -0,0 +1,61 @@
+import { find } from 'lodash'
+
+const createFaviconService = () => {
+ let favimg, favcanvas, favcontext, favicon
+ const faviconWidth = 128
+ const faviconHeight = 128
+ const badgeRadius = 32
+
+ const initFaviconService = () => {
+ const nodes = document.getElementsByTagName('link')
+ favicon = find(nodes, node => node.rel === 'icon')
+ if (favicon) {
+ favcanvas = document.createElement('canvas')
+ favcanvas.width = faviconWidth
+ favcanvas.height = faviconHeight
+ favimg = new Image()
+ favimg.src = favicon.href
+ favcontext = favcanvas.getContext('2d')
+ }
+ }
+
+ const isImageLoaded = (img) => img.complete && img.naturalHeight !== 0
+
+ const clearFaviconBadge = () => {
+ if (!favimg || !favcontext || !favicon) return
+
+ favcontext.clearRect(0, 0, faviconWidth, faviconHeight)
+ if (isImageLoaded(favimg)) {
+ favcontext.drawImage(favimg, 0, 0, favimg.width, favimg.height, 0, 0, faviconWidth, faviconHeight)
+ }
+ favicon.href = favcanvas.toDataURL('image/png')
+ }
+
+ const drawFaviconBadge = () => {
+ if (!favimg || !favcontext || !favcontext) return
+
+ clearFaviconBadge()
+
+ const style = getComputedStyle(document.body)
+ const badgeColor = `${style.getPropertyValue('--badgeNotification') || 'rgb(240, 100, 100)'}`
+
+ if (isImageLoaded(favimg)) {
+ favcontext.drawImage(favimg, 0, 0, favimg.width, favimg.height, 0, 0, faviconWidth, faviconHeight)
+ }
+ favcontext.fillStyle = badgeColor
+ favcontext.beginPath()
+ favcontext.arc(faviconWidth - badgeRadius, badgeRadius, badgeRadius, 0, 2 * Math.PI, false)
+ favcontext.fill()
+ favicon.href = favcanvas.toDataURL('image/png')
+ }
+
+ return {
+ initFaviconService,
+ clearFaviconBadge,
+ drawFaviconBadge
+ }
+}
+
+const FaviconService = createFaviconService()
+
+export default FaviconService