Skip to content

Commit 3c1295b

Browse files
authored
Merge pull request #28 from jaulz/fix/configurable-height
feat: add configurable height
2 parents 9a19ee7 + 43d80c9 commit 3c1295b

File tree

3 files changed

+69
-33
lines changed

3 files changed

+69
-33
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Badgin
22

3-
The [Badging API](https://web.dev/badging-api/) is a new web platform API that allows installed web apps to set an application-wide badge, shown in an operating-system-specific place associated with the application (such as the shelf or home screen). Starting in Chrome 73, the Badging API is available as an origin trial for Windows (7+) and macOS. If you want to know how origin trials work, please check the[documentation](https://web.dev/badging-api/#ot). Since this API is not available everywhere, `badgin` safely falls back to alternatives.
3+
The [Badging API](https://web.dev/badging-api/) is a new web platform API that allows installed web apps to set an application-wide badge, shown in an operating-system-specific place associated with the application (such as the shelf or home screen). Starting in Chrome 73, the Badging API is available as an origin trial for Windows (7+) and macOS. If you want to know how origin trials work, please check the [documentation](https://web.dev/badging-api/#ot). Since this API is not available everywhere, `badgin` safely falls back to alternatives.
44

55
## via badge
66

index.html

+18-6
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,29 @@ <h1 class="title">Value</h1>
169169
</style>
170170

171171
<script>
172-
const isLocalhost =
173-
location.hostname === 'localhost' || location.hostname === '127.0.0.1'
172+
const isDevelopment =
173+
location.hostname === 'localhost' ||
174+
location.hostname === '127.0.0.1' ||
175+
location.hostname.endsWith('codespaces.githubusercontent.com')
174176
let value = 0
175177
const options = {
176-
favicon: {},
178+
favicon: {
179+
backgroundColor: '#000000',
180+
color: '#FFFFFF',
181+
indicator: '@',
182+
radius: 3,
183+
size: 7,
184+
horizontalMargin: 1,
185+
verticalMargin: 1,
186+
horizontalPadding: 2,
187+
verticalPadding: 2,
188+
},
177189
}
178190

179191
document.getElementById('set').addEventListener('click', () => {
180192
const value = document.getElementById('value').value
181193
localStorage.setItem('value', value)
182-
badgin.set(value ? parseInt(value, 10) : value, options)
194+
badgin.set(value ? parseInt(value, 10) : undefined, options)
183195
})
184196

185197
document.getElementById('clear').addEventListener('click', () => {
@@ -223,15 +235,15 @@ <h1 class="title">Value</h1>
223235
})
224236

225237
// Add service worker
226-
if (!isLocalhost && 'serviceWorker' in navigator) {
238+
if (!isDevelopment && 'serviceWorker' in navigator) {
227239
navigator.serviceWorker.register('./sw.js').then(() => {
228240
console.log('Service Worker Registered')
229241
})
230242
}
231243

232244
// Load script
233245
const script = document.createElement('script')
234-
script.src = isLocalhost
246+
script.src = isDevelopment
235247
? '/build/index.iife.js'
236248
: 'https://unpkg.com/badgin/build/index.iife.js'
237249
script.onload = () => {

src/favicon.ts

+50-26
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ export type Options = {
77
color: string
88
indicator: string
99
radius: number
10+
size: number
11+
horizontalMargin: number
12+
verticalMargin: number
13+
horizontalPadding: number
14+
verticalPadding: number
1015
}
1116

1217
type Favicon = HTMLLinkElement
@@ -20,6 +25,11 @@ export const DefaultOptions: Options = {
2025
color: '#ffffff',
2126
indicator: '!',
2227
radius: 3,
28+
size: 7,
29+
horizontalMargin: 0,
30+
verticalMargin: 0,
31+
horizontalPadding: 1,
32+
verticalPadding: 1,
2333
}
2434

2535
// Get all favicons of the page
@@ -119,10 +129,9 @@ const getRatio = () => {
119129
return Math.ceil(window.devicePixelRatio) || 1
120130
}
121131
const handleRatioChange = () => {
122-
console.log('handleRatioChange')
123132
set(current.value, current.options)
124133
}
125-
const getSize = () => {
134+
const getIconSize = () => {
126135
return 16 * getRatio()
127136
}
128137

@@ -155,18 +164,18 @@ const drawFavicon = (
155164
value: Value,
156165
options: Options
157166
) => {
158-
const size = getSize()
167+
const iconSize = getIconSize()
159168
const canvas = document.createElement('canvas')
160-
canvas.width = size
161-
canvas.height = size
169+
canvas.width = iconSize
170+
canvas.height = iconSize
162171
const context = canvas.getContext('2d')
163172
if (!context) {
164173
return
165174
}
166175

167176
// Draw new image
168-
image.width = size
169-
image.height = size
177+
image.width = iconSize
178+
image.height = iconSize
170179
context.drawImage(image, 0, 0, image.width, image.height)
171180

172181
// Draw bubble on the top
@@ -182,6 +191,9 @@ const drawBubble = (
182191
value: Value,
183192
options: Options
184193
) => {
194+
const ratio = getRatio()
195+
const iconSize = getIconSize()
196+
185197
// Do we need to render the bubble at all?
186198
let finalValue: string = ''
187199
if (isPositiveNumber(value)) {
@@ -201,24 +213,27 @@ const drawBubble = (
201213
return
202214
}
203215

216+
// Calculate text width initially
217+
const textHeight = options.size - 2
218+
const font = `${options.size * ratio}px Arial`
219+
context.font = font
220+
const { width: textWidth } = context.measureText(finalValue)
221+
context.restore()
222+
204223
// Calculate position etc.
205-
const size = getSize()
206-
const ratio = getRatio()
207-
const length = finalValue.length - 1
208-
const width = Math.min(8 * ratio + 4 * ratio * length, size)
209-
const height = 7 * ratio
210-
const top = size - height
211-
const left = size - width
212-
const bottom = 16 * ratio
213-
const right = 16 * ratio
214-
const radius = options.radius * ratio
224+
const width = textWidth + 2 * options.horizontalPadding
225+
const height = textHeight * ratio + 2 * options.verticalPadding
226+
const top = iconSize - height - options.verticalMargin
227+
const left = iconSize - width - options.horizontalMargin
228+
const bottom = 16 * ratio - options.verticalMargin
229+
const right = 16 * ratio - options.horizontalMargin
230+
const radius = options.radius
215231

216232
// Bubble
217-
context.save()
218233
context.globalAlpha = 1
219234
context.fillStyle = options.backgroundColor
220235
context.strokeStyle = options.backgroundColor
221-
context.lineWidth = ratio
236+
context.lineWidth = 0
222237
context.beginPath()
223238
context.moveTo(left + radius, top)
224239
context.quadraticCurveTo(left, top, left, top + radius)
@@ -230,16 +245,25 @@ const drawBubble = (
230245
context.quadraticCurveTo(right, top, right - radius, top)
231246
context.closePath()
232247
context.fill()
233-
context.restore()
248+
context.save()
234249

235250
// Value
236-
context.save()
237-
context.font = `${7 * ratio}px Arial`
251+
context.font = font
238252
context.fillStyle = options.color
239253
context.textAlign = 'center'
240-
context.textBaseline = 'top'
241-
context.fillText(finalValue, left + width / 2, 9 * ratio + 1)
254+
context.textBaseline = 'hanging'
255+
context.fillText(finalValue, left + width / 2, top + options.verticalPadding)
256+
context.save()
257+
258+
/*
259+
// Helper line
242260
context.restore()
261+
context.strokeStyle = '#ff0000'
262+
context.moveTo(0, top + height / 2)
263+
context.lineTo(iconSize, top + height / 2)
264+
context.stroke()
265+
context.save()
266+
*/
243267
}
244268

245269
export function isAvailable() {
@@ -276,7 +300,7 @@ export function set(value: Value, options?: Partial<Options>) {
276300
}
277301

278302
// Once the device pixel ratio changes we set the value again
279-
devicePixelRatioListener.addListener(handleRatioChange)
303+
devicePixelRatioListener.addEventListener('change', handleRatioChange)
280304
}
281305
if (!current.favicons) {
282306
current.favicons = getFavicons()
@@ -311,7 +335,7 @@ export function clear() {
311335
current.options = DefaultOptions
312336

313337
// Remove old listener
314-
devicePixelRatioListener.removeListener(handleRatioChange)
338+
devicePixelRatioListener.removeEventListener('change', handleRatioChange)
315339

316340
if (current.favicons) {
317341
// Remove current favicons

0 commit comments

Comments
 (0)