tiny-essentials 1.10.2 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{TinyEssentials.js → v1/TinyEssentials.js} +804 -0
- package/dist/v1/TinyEssentials.min.js +2 -0
- package/dist/v1/TinyNotifyCenter.js +461 -0
- package/dist/v1/TinyNotifyCenter.min.js +1 -0
- package/dist/v1/TinyToastNotify.js +417 -0
- package/dist/v1/TinyToastNotify.min.js +1 -0
- package/dist/v1/build/TinyNotifyCenter.cjs +7 -0
- package/dist/v1/build/TinyNotifyCenter.d.mts +3 -0
- package/dist/v1/build/TinyNotifyCenter.mjs +2 -0
- package/dist/v1/build/TinyToastNotify.cjs +7 -0
- package/dist/v1/build/TinyToastNotify.d.mts +3 -0
- package/dist/v1/build/TinyToastNotify.mjs +2 -0
- package/dist/v1/css/TinyNotify.css +350 -0
- package/dist/v1/css/TinyNotify.min.css +1 -0
- package/dist/v1/index.cjs +4 -0
- package/dist/v1/index.d.mts +3 -1
- package/dist/v1/index.mjs +3 -1
- package/dist/v1/libs/TinyNotifyCenter.cjs +422 -0
- package/dist/v1/libs/TinyNotifyCenter.d.mts +166 -0
- package/dist/v1/libs/TinyNotifyCenter.mjs +385 -0
- package/dist/v1/libs/TinyToastNotify.cjs +378 -0
- package/dist/v1/libs/TinyToastNotify.d.mts +157 -0
- package/dist/v1/libs/TinyToastNotify.mjs +332 -0
- package/docs/{README.md → v1/README.md} +2 -0
- package/docs/{basics → v1/basics}/text.md +2 -2
- package/docs/v1/libs/TinyNotifyCenter.md +291 -0
- package/docs/v1/libs/TinyToastNotify.md +290 -0
- package/package.json +4 -2
- package/dist/TinyEssentials.min.js +0 -2
- package/dist/v1/libs/TinyRateLimit.cjs +0 -196
- package/dist/v1/libs/TinyRateLimit.d.mts +0 -86
- package/dist/v1/libs/TinyRateLimit.mjs +0 -171
- /package/dist/{ColorSafeStringify.js → v1/ColorSafeStringify.js} +0 -0
- /package/dist/{ColorSafeStringify.min.js → v1/ColorSafeStringify.min.js} +0 -0
- /package/dist/{TinyBasicsEs.js → v1/TinyBasicsEs.js} +0 -0
- /package/dist/{TinyBasicsEs.min.js → v1/TinyBasicsEs.min.js} +0 -0
- /package/dist/{TinyBasicsEs.min.js.LICENSE.txt → v1/TinyBasicsEs.min.js.LICENSE.txt} +0 -0
- /package/dist/{TinyEssentials.min.js.LICENSE.txt → v1/TinyEssentials.min.js.LICENSE.txt} +0 -0
- /package/dist/{TinyLevelUp.js → v1/TinyLevelUp.js} +0 -0
- /package/dist/{TinyLevelUp.min.js → v1/TinyLevelUp.min.js} +0 -0
- /package/dist/{TinyPromiseQueue.js → v1/TinyPromiseQueue.js} +0 -0
- /package/dist/{TinyPromiseQueue.min.js → v1/TinyPromiseQueue.min.js} +0 -0
- /package/dist/{TinyRateLimiter.js → v1/TinyRateLimiter.js} +0 -0
- /package/dist/{TinyRateLimiter.min.js → v1/TinyRateLimiter.min.js} +0 -0
- /package/dist/{aiMarker.css → v1/css/aiMarker.css} +0 -0
- /package/dist/{aiMarker.min.css → v1/css/aiMarker.min.css} +0 -0
- /package/docs/{basics → v1/basics}/array.md +0 -0
- /package/docs/{basics → v1/basics}/asyncReplace.md +0 -0
- /package/docs/{basics → v1/basics}/clock.md +0 -0
- /package/docs/{basics → v1/basics}/objFilter.md +0 -0
- /package/docs/{basics → v1/basics}/simpleMath.md +0 -0
- /package/docs/{libs → v1/libs}/ColorSafeStringify.md +0 -0
- /package/docs/{libs → v1/libs}/TinyLevelUp.md +0 -0
- /package/docs/{libs → v1/libs}/TinyPromiseQueue.md +0 -0
- /package/docs/{libs → v1/libs}/TinyRateLimiter.md +0 -0
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A callback function used to manually close a notification.
|
|
3
|
+
* Passed as a second argument to `onClick` handlers, allowing programmatic dismissal of the toast.
|
|
4
|
+
*
|
|
5
|
+
* @typedef {() => void} CloseToastFunc
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Represents the data used to display a notification.
|
|
9
|
+
* Can be a plain string (used as the message), or an object with more customization options.
|
|
10
|
+
*
|
|
11
|
+
* @typedef {string | {
|
|
12
|
+
* message: string, // The main message to display
|
|
13
|
+
* title?: string, // Optional title to appear above the message
|
|
14
|
+
* onClick?: function(MouseEvent, CloseToastFunc): void, // Optional click handler for the notification
|
|
15
|
+
* html?: boolean, // Whether the message should be interpreted as raw HTML
|
|
16
|
+
* avatar?: string // Optional URL to an avatar image shown on the left
|
|
17
|
+
* }} NotifyData
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* A lightweight notification system designed to display timed messages inside a container.
|
|
21
|
+
* Supports positioning, timing customization, click actions, HTML content, and optional avatars.
|
|
22
|
+
*
|
|
23
|
+
* ## Features:
|
|
24
|
+
* - Positioning via `x` (`left`, `center`, `right`) and `y` (`top`, `bottom`).
|
|
25
|
+
* - Dynamic display time based on message length.
|
|
26
|
+
* - Optional `title`, `avatar`, `onClick`, and `html` message rendering.
|
|
27
|
+
* - Fade-out animation with customizable duration.
|
|
28
|
+
* - Rigid validation of inputs and internal state.
|
|
29
|
+
*
|
|
30
|
+
* ## Customization via setters:
|
|
31
|
+
* - `setX(position)` — horizontal alignment.
|
|
32
|
+
* - `setY(position)` — vertical alignment.
|
|
33
|
+
* - `setBaseDuration(ms)` — base visible time in milliseconds.
|
|
34
|
+
* - `setExtraPerChar(ms)` — extra time added per character.
|
|
35
|
+
* - `setFadeOutDuration(ms)` — fade-out animation duration in milliseconds.
|
|
36
|
+
*
|
|
37
|
+
* @class
|
|
38
|
+
*/
|
|
39
|
+
class TinyToastNotify {
|
|
40
|
+
#y;
|
|
41
|
+
#x;
|
|
42
|
+
#baseDuration;
|
|
43
|
+
#extraPerChar;
|
|
44
|
+
#fadeOutDuration;
|
|
45
|
+
#container;
|
|
46
|
+
/**
|
|
47
|
+
* @param {'top'|'bottom'} y - 'top' or 'bottom'
|
|
48
|
+
* @param {'right'|'left'|'center'} x - 'right', 'left', or 'center'
|
|
49
|
+
* @param {number} baseDuration - Base display time in ms
|
|
50
|
+
* @param {number} extraPerChar - Extra ms per character
|
|
51
|
+
* @param {number} fadeOutDuration - Time in ms for fade-out effect
|
|
52
|
+
* @param {string} [selector='.notify-container'] - Base selector for container
|
|
53
|
+
*/
|
|
54
|
+
constructor(y = 'top', x = 'right', baseDuration = 3000, extraPerChar = 50, fadeOutDuration = 300, selector = '.notify-container') {
|
|
55
|
+
this.#validateY(y);
|
|
56
|
+
this.#validateX(x);
|
|
57
|
+
this.#validateTiming(baseDuration, 'baseDuration');
|
|
58
|
+
this.#validateTiming(extraPerChar, 'extraPerChar');
|
|
59
|
+
this.#validateTiming(fadeOutDuration, 'fadeOutDuration');
|
|
60
|
+
this.#y = y;
|
|
61
|
+
this.#x = x;
|
|
62
|
+
this.#baseDuration = baseDuration;
|
|
63
|
+
this.#extraPerChar = extraPerChar;
|
|
64
|
+
this.#fadeOutDuration = fadeOutDuration;
|
|
65
|
+
const container = document.querySelector(`${selector}.${y}.${x}`);
|
|
66
|
+
if (!(container instanceof HTMLElement)) {
|
|
67
|
+
this.#container = document.createElement('div');
|
|
68
|
+
this.#container.className = `notify-container ${y} ${x}`;
|
|
69
|
+
document.body.appendChild(this.#container);
|
|
70
|
+
}
|
|
71
|
+
else
|
|
72
|
+
this.#container = container;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the notification container element.
|
|
76
|
+
* Ensures that the container is a valid HTMLElement.
|
|
77
|
+
*
|
|
78
|
+
* @returns {HTMLElement} The notification container.
|
|
79
|
+
* @throws {Error} If the container is not a valid HTMLElement.
|
|
80
|
+
*/
|
|
81
|
+
getContainer() {
|
|
82
|
+
if (!(this.#container instanceof HTMLElement))
|
|
83
|
+
throw new Error('Container is not a valid HTMLElement.');
|
|
84
|
+
return this.#container;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Validates the vertical position value.
|
|
88
|
+
* Must be either 'top' or 'bottom'.
|
|
89
|
+
*
|
|
90
|
+
* @param {string} value - The vertical position to validate.
|
|
91
|
+
* @throws {Error} If the value is not 'top' or 'bottom'.
|
|
92
|
+
*/
|
|
93
|
+
#validateY(value) {
|
|
94
|
+
if (!['top', 'bottom'].includes(value)) {
|
|
95
|
+
throw new Error(`Invalid vertical direction "${value}". Expected "top" or "bottom".`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Validates the horizontal position value.
|
|
100
|
+
* Must be 'left', 'right', or 'center'.
|
|
101
|
+
*
|
|
102
|
+
* @param {string} value - The horizontal position to validate.
|
|
103
|
+
* @throws {Error} If the value is not one of the accepted directions.
|
|
104
|
+
*/
|
|
105
|
+
#validateX(value) {
|
|
106
|
+
if (!['left', 'right', 'center'].includes(value)) {
|
|
107
|
+
throw new Error(`Invalid horizontal position "${value}". Expected "left", "right" or "center".`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Validates a numeric timing value.
|
|
112
|
+
* Must be a non-negative finite number.
|
|
113
|
+
*
|
|
114
|
+
* @param {number} value - The number to validate.
|
|
115
|
+
* @param {string} name - The name of the parameter (used for error messaging).
|
|
116
|
+
* @throws {Error} If the number is invalid.
|
|
117
|
+
*/
|
|
118
|
+
#validateTiming(value, name) {
|
|
119
|
+
if (typeof value !== 'number' || value < 0 || !Number.isFinite(value)) {
|
|
120
|
+
throw new Error(`Invalid value for "${name}": ${value}. Must be a non-negative finite number.`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Returns the current vertical position.
|
|
125
|
+
*
|
|
126
|
+
* @returns {'top'|'bottom'} The vertical direction of the notification container.
|
|
127
|
+
*/
|
|
128
|
+
getY() {
|
|
129
|
+
return this.#y;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Sets the vertical position of the notification container.
|
|
133
|
+
* Updates the container's class to reflect the new position.
|
|
134
|
+
*
|
|
135
|
+
* @param {'top'|'bottom'} value - The vertical direction to set.
|
|
136
|
+
* @throws {Error} If the value is invalid.
|
|
137
|
+
*/
|
|
138
|
+
setY(value) {
|
|
139
|
+
this.#validateY(value);
|
|
140
|
+
const container = this.getContainer();
|
|
141
|
+
container.classList.remove(this.#y);
|
|
142
|
+
container.classList.add(value);
|
|
143
|
+
this.#y = value;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns the current horizontal position.
|
|
147
|
+
*
|
|
148
|
+
* @returns {'left'|'right'|'center'} The horizontal direction of the notification container.
|
|
149
|
+
*/
|
|
150
|
+
getX() {
|
|
151
|
+
return this.#x;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Sets the horizontal position of the notification container.
|
|
155
|
+
* Updates the container's class to reflect the new position.
|
|
156
|
+
*
|
|
157
|
+
* @param {'left'|'right'|'center'} value - The horizontal direction to set.
|
|
158
|
+
* @throws {Error} If the value is invalid.
|
|
159
|
+
*/
|
|
160
|
+
setX(value) {
|
|
161
|
+
this.#validateX(value);
|
|
162
|
+
const container = this.getContainer();
|
|
163
|
+
container.classList.remove(this.#x);
|
|
164
|
+
container.classList.add(value);
|
|
165
|
+
this.#x = value;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Returns the base duration for displaying the notification.
|
|
169
|
+
*
|
|
170
|
+
* @returns {number} Base time (in milliseconds) that a notification stays on screen.
|
|
171
|
+
*/
|
|
172
|
+
getBaseDuration() {
|
|
173
|
+
return this.#baseDuration;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Sets the base duration for the notification display time.
|
|
177
|
+
*
|
|
178
|
+
* @param {number} value - Base display time in milliseconds.
|
|
179
|
+
* @throws {Error} If the value is not a valid non-negative finite number.
|
|
180
|
+
*/
|
|
181
|
+
setBaseDuration(value) {
|
|
182
|
+
this.#validateTiming(value, 'baseDuration');
|
|
183
|
+
this.#baseDuration = value;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Returns the extra display time added per character.
|
|
187
|
+
*
|
|
188
|
+
* @returns {number} Extra time (in milliseconds) per character in the notification.
|
|
189
|
+
*/
|
|
190
|
+
getExtraPerChar() {
|
|
191
|
+
return this.#extraPerChar;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Sets the additional display time per character.
|
|
195
|
+
*
|
|
196
|
+
* @param {number} value - Extra time in milliseconds per character.
|
|
197
|
+
* @throws {Error} If the value is not a valid non-negative finite number.
|
|
198
|
+
*/
|
|
199
|
+
setExtraPerChar(value) {
|
|
200
|
+
this.#validateTiming(value, 'extraPerChar');
|
|
201
|
+
this.#extraPerChar = value;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Returns the fade-out duration.
|
|
205
|
+
*
|
|
206
|
+
* @returns {number} Time (in milliseconds) used for fade-out transition.
|
|
207
|
+
*/
|
|
208
|
+
getFadeOutDuration() {
|
|
209
|
+
return this.#fadeOutDuration;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Sets the fade-out transition time for notifications.
|
|
213
|
+
*
|
|
214
|
+
* @param {number} value - Fade-out duration in milliseconds.
|
|
215
|
+
* @throws {Error} If the value is not a valid non-negative finite number.
|
|
216
|
+
*/
|
|
217
|
+
setFadeOutDuration(value) {
|
|
218
|
+
this.#validateTiming(value, 'fadeOutDuration');
|
|
219
|
+
this.#fadeOutDuration = value;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Displays a notification for a time based on message length.
|
|
223
|
+
* Accepts a string or an object with:
|
|
224
|
+
* {
|
|
225
|
+
* message: string,
|
|
226
|
+
* title?: string,
|
|
227
|
+
* onClick?: function(MouseEvent, CloseToastFunc): void,
|
|
228
|
+
* html?: boolean,
|
|
229
|
+
* avatar?: string // Optional avatar image URL
|
|
230
|
+
* }
|
|
231
|
+
*
|
|
232
|
+
* @param {NotifyData} data
|
|
233
|
+
*/
|
|
234
|
+
show(data) {
|
|
235
|
+
let message = '';
|
|
236
|
+
let title = '';
|
|
237
|
+
let onClick = null;
|
|
238
|
+
let useHTML = false;
|
|
239
|
+
let avatarUrl = null;
|
|
240
|
+
const notify = document.createElement('div');
|
|
241
|
+
notify.className = 'notify enter';
|
|
242
|
+
if (typeof data === 'string') {
|
|
243
|
+
message = data;
|
|
244
|
+
}
|
|
245
|
+
else if (typeof data === 'object' && data !== null && typeof data.message === 'string') {
|
|
246
|
+
message = data.message;
|
|
247
|
+
title = typeof data.title === 'string' ? data.title : '';
|
|
248
|
+
useHTML = data.html === true;
|
|
249
|
+
avatarUrl = typeof data.avatar === 'string' ? data.avatar : null;
|
|
250
|
+
if (data.onClick !== undefined) {
|
|
251
|
+
if (typeof data.onClick !== 'function') {
|
|
252
|
+
throw new Error('onClick must be a function if defined');
|
|
253
|
+
}
|
|
254
|
+
onClick = data.onClick;
|
|
255
|
+
notify.classList.add('clickable');
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
throw new Error(`Invalid argument for show(): expected string or { message: string, title?: string, onClick?: function, html?: boolean, avatar?: string }`);
|
|
260
|
+
}
|
|
261
|
+
// Add close button
|
|
262
|
+
const closeBtn = document.createElement('button');
|
|
263
|
+
closeBtn.innerHTML = '×';
|
|
264
|
+
closeBtn.className = 'close';
|
|
265
|
+
closeBtn.setAttribute('aria-label', 'Close');
|
|
266
|
+
// Optional hover effect
|
|
267
|
+
closeBtn.addEventListener('mouseenter', () => {
|
|
268
|
+
closeBtn.style.color = 'var(--notif-close-color-hover)';
|
|
269
|
+
});
|
|
270
|
+
closeBtn.addEventListener('mouseleave', () => {
|
|
271
|
+
closeBtn.style.color = 'var(--notif-close-color)';
|
|
272
|
+
});
|
|
273
|
+
// Avatar
|
|
274
|
+
if (avatarUrl) {
|
|
275
|
+
const avatar = document.createElement('img');
|
|
276
|
+
avatar.src = avatarUrl;
|
|
277
|
+
avatar.alt = 'avatar';
|
|
278
|
+
avatar.className = 'avatar';
|
|
279
|
+
notify.appendChild(avatar);
|
|
280
|
+
}
|
|
281
|
+
// Title
|
|
282
|
+
if (title) {
|
|
283
|
+
const titleElem = document.createElement('strong');
|
|
284
|
+
titleElem.textContent = title;
|
|
285
|
+
titleElem.style.display = 'block';
|
|
286
|
+
notify.appendChild(titleElem);
|
|
287
|
+
}
|
|
288
|
+
// Message
|
|
289
|
+
if (useHTML) {
|
|
290
|
+
const msgWrapper = document.createElement('div');
|
|
291
|
+
msgWrapper.innerHTML = message;
|
|
292
|
+
notify.appendChild(msgWrapper);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
notify.appendChild(document.createTextNode(message));
|
|
296
|
+
}
|
|
297
|
+
notify.appendChild(closeBtn);
|
|
298
|
+
this.getContainer().appendChild(notify);
|
|
299
|
+
const visibleTime = this.#baseDuration + message.length * this.#extraPerChar;
|
|
300
|
+
const totalTime = visibleTime + this.#fadeOutDuration;
|
|
301
|
+
// Close logic
|
|
302
|
+
let removed = false;
|
|
303
|
+
const close = () => {
|
|
304
|
+
if (removed)
|
|
305
|
+
return;
|
|
306
|
+
removed = true;
|
|
307
|
+
notify.classList.remove('enter', 'show');
|
|
308
|
+
notify.classList.add('exit');
|
|
309
|
+
setTimeout(() => notify.remove(), this.#fadeOutDuration);
|
|
310
|
+
};
|
|
311
|
+
// Click handler
|
|
312
|
+
if (typeof onClick === 'function') {
|
|
313
|
+
notify.addEventListener('click', (e) => {
|
|
314
|
+
if (e.target === closeBtn)
|
|
315
|
+
return;
|
|
316
|
+
onClick(e, close);
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
// Close button click
|
|
320
|
+
closeBtn.addEventListener('click', (e) => {
|
|
321
|
+
e.stopPropagation();
|
|
322
|
+
close();
|
|
323
|
+
});
|
|
324
|
+
// Transition activation force soon after the element is added
|
|
325
|
+
setTimeout(() => {
|
|
326
|
+
notify.classList.remove('enter');
|
|
327
|
+
notify.classList.add('show');
|
|
328
|
+
}, 1);
|
|
329
|
+
setTimeout(() => close(), totalTime);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
export default TinyToastNotify;
|
|
@@ -24,6 +24,8 @@ This folder contains the core scripts we have worked on so far. Each file is a m
|
|
|
24
24
|
- 🏅 **[TinyLevelUp](./libs/TinyLevelUp.md)** — A class to manage user level-up logic based on experience points, providing methods for experience validation, addition, removal, and calculation.
|
|
25
25
|
- 🎨 **[ColorSafeStringify](./libs/ColorSafeStringify.md)** — A utility for applying customizable ANSI colors to JSON strings in terminal outputs, supporting presets and fine-grained type-based highlighting.
|
|
26
26
|
- 🚦 **[TinyRateLimiter](./libs/TinyRateLimiter.md)** — A flexible per-user rate limiter supporting time windows, hit caps, and automatic cleanup of inactive users.
|
|
27
|
+
* 🔔 **[TinyNotifyCenter](./libs/TinyNotifyCenter.md)** — A dynamic notification center class to display, manage, and interact with notifications, supporting avatars, clickable items, HTML/text modes, and clean UI controls.
|
|
28
|
+
* 🍞 **[TinyToastNotify](./libs/TinyToastNotify.md)** — A lightweight toast notification system supporting positioning, timing customization, avatars, click actions, and fade-out animations.
|
|
27
29
|
|
|
28
30
|
---
|
|
29
31
|
|
|
@@ -123,7 +123,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
123
123
|
|
|
124
124
|
You can use a pre-built CSS template for the `detect-made-by-ai` class, available in the following files:
|
|
125
125
|
|
|
126
|
-
* `/dist/aiMarker.min.css` – A minified version of the CSS for production use.
|
|
127
|
-
* `/dist/aiMarker.css` – The non-minified version for easier readability and customization.
|
|
126
|
+
* `/dist/v1/css/aiMarker.min.css` – A minified version of the CSS for production use.
|
|
127
|
+
* `/dist/v1/css/aiMarker.css` – The non-minified version for easier readability and customization.
|
|
128
128
|
|
|
129
129
|
Simply include the appropriate file in your project to style the elements marked with the `detect-made-by-ai` class.
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# 🛎️ TinyNotifyCenter
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`TinyNotifyCenter` is a notification center component designed to display interactive alerts in the UI.
|
|
6
|
+
|
|
7
|
+
This class renders a notification overlay on the page, allowing dynamic management of notification items — adding, clearing, and interacting with them in real time.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🔔 NotifyData Type
|
|
12
|
+
|
|
13
|
+
A notification entry (`NotifyData`) can be either a simple string or an object with extra data:
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
type NotifyData = string | {
|
|
17
|
+
title?: string; // Optional title shown above the message
|
|
18
|
+
message: string; // Required message content (plain text or HTML)
|
|
19
|
+
avatar?: string; // Optional avatar image URL (displayed on the left)
|
|
20
|
+
onClick?: (e: MouseEvent) => void; // Optional click handler for the entire notification
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ✨ Features
|
|
27
|
+
|
|
28
|
+
* Dynamic rendering of notification UI via the `insertTemplate()` method
|
|
29
|
+
* Supports both plain text and HTML content in notifications
|
|
30
|
+
* Optional avatars shown alongside notifications
|
|
31
|
+
* Supports callback functions on notification click events
|
|
32
|
+
* Each notification includes a close button for dismissal
|
|
33
|
+
* Displays a badge with the count of active notifications
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🏗️ Static Methods
|
|
38
|
+
|
|
39
|
+
### `static getTemplate() : string`
|
|
40
|
+
|
|
41
|
+
Returns the full HTML structure for the notification system as a **string**.
|
|
42
|
+
|
|
43
|
+
This template includes:
|
|
44
|
+
|
|
45
|
+
- A hidden `.notify-overlay` element containing the central notification panel (`#notifCenter`):
|
|
46
|
+
- Header with a **"Notifications"** label
|
|
47
|
+
- A **clear all** button (with checkmark icon)
|
|
48
|
+
- A **close** button (×)
|
|
49
|
+
- A `.list` container to hold dynamically added notification items
|
|
50
|
+
- A bell button (`.notify-bell`) to toggle the notification center, featuring:
|
|
51
|
+
- A bell SVG icon
|
|
52
|
+
- A badge (`#notifBadge`) displaying the number of active notifications
|
|
53
|
+
|
|
54
|
+
> 💡 This HTML can be injected into the DOM using methods like `insertAdjacentHTML()` or parsed into elements with JavaScript or jQuery.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
### `static insertTemplate(where = 'afterbegin') : void`
|
|
59
|
+
|
|
60
|
+
Injects the full notification center HTML template into the `document.body`.
|
|
61
|
+
|
|
62
|
+
- Uses `insertAdjacentHTML()` to insert the markup.
|
|
63
|
+
- The `where` parameter controls the insertion point relative to the `<body>` element.
|
|
64
|
+
|
|
65
|
+
Possible values for `where`:
|
|
66
|
+
|
|
67
|
+
| Value | Description |
|
|
68
|
+
|---------------|------------------------------------------|
|
|
69
|
+
| `'afterbegin'` (default) | Insert right after the opening `<body>` tag |
|
|
70
|
+
| `'beforeend'` | Insert right before the closing `</body>` tag |
|
|
71
|
+
| `'beforebegin'` or `'afterend'` | Other valid positions supported by `insertAdjacentHTML` |
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
### Example Usage
|
|
76
|
+
|
|
77
|
+
```js
|
|
78
|
+
// Insert notification center template at the start of <body>
|
|
79
|
+
TinyNotifyCenter.insertTemplate();
|
|
80
|
+
|
|
81
|
+
// Or insert at the end of <body>
|
|
82
|
+
TinyNotifyCenter.insertTemplate('beforeend');
|
|
83
|
+
````
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
### Visual Structure Preview
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<div class="notify-overlay hidden">
|
|
91
|
+
<div class="notify-center" id="notifCenter">
|
|
92
|
+
<div class="header">
|
|
93
|
+
<div>Notifications</div>
|
|
94
|
+
<div class="options">
|
|
95
|
+
<button class="clear-all" type="button">✔️</button>
|
|
96
|
+
<button class="close">×</button>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="list"></div>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<button class="notify-bell" aria-label="Open notifications">
|
|
104
|
+
🔔 <span class="badge" id="notifBadge">0</span>
|
|
105
|
+
</button>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 🛠️ Instance Methods & Constructor
|
|
111
|
+
|
|
112
|
+
### `constructor(options = {})`
|
|
113
|
+
|
|
114
|
+
Creates a new instance of the Notification Center with configurable main elements.
|
|
115
|
+
|
|
116
|
+
| Option | Default Selector | Description |
|
|
117
|
+
|-----------------|----------------------------------------|----------------------------------------------|
|
|
118
|
+
| `center` | `document.getElementById('notifCenter')` | Container element holding notification list |
|
|
119
|
+
| `badge` | `document.getElementById('notifBadge')` | Badge element showing the notification count |
|
|
120
|
+
| `button` | `document.querySelector('.notify-bell')` | Button toggling the notification center |
|
|
121
|
+
| `overlay` | `document.querySelector('.notify-overlay')` | Overlay element shown when center is visible |
|
|
122
|
+
|
|
123
|
+
⚠️ Throws an error if any of the elements are not valid HTMLElements.
|
|
124
|
+
|
|
125
|
+
**Event Listeners added internally:**
|
|
126
|
+
|
|
127
|
+
- `button` click → toggles notification center
|
|
128
|
+
- `close` button inside center → closes notification center
|
|
129
|
+
- `clear-all` button inside center → clears all notifications
|
|
130
|
+
- Clicking the overlay outside center → closes notification center
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
### ⚙️ Configuration Methods
|
|
135
|
+
|
|
136
|
+
#### `setMarkAllAsReadOnClose(value: boolean)`
|
|
137
|
+
|
|
138
|
+
Enable or disable automatic marking of all notifications as read when the center closes.
|
|
139
|
+
|
|
140
|
+
Throws a `TypeError` if `value` is not a boolean.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
#### `setRemoveDelay(ms: number)`
|
|
145
|
+
|
|
146
|
+
Set the delay (in milliseconds) for the remove animation when notifications are removed.
|
|
147
|
+
|
|
148
|
+
Throws an error if `ms` is not a number.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
### 📋 Notification Item Accessors
|
|
153
|
+
|
|
154
|
+
#### `getItemMode(index: number) : 'text' | 'html' | null`
|
|
155
|
+
|
|
156
|
+
Returns the rendering mode (`'text'` or `'html'`) of the notification at the given index, or `null` if not found.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
#### `getItem(index: number) : HTMLElement`
|
|
161
|
+
|
|
162
|
+
Returns the notification element at the specified index.
|
|
163
|
+
|
|
164
|
+
Throws an error if the element is not an `HTMLElement`.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
#### `hasItem(index: number) : boolean`
|
|
169
|
+
|
|
170
|
+
Returns `true` if a notification exists at the given index, `false` otherwise.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
### ✅ Notification State Management
|
|
175
|
+
|
|
176
|
+
#### `markAsRead(index: number | HTMLElement)`
|
|
177
|
+
|
|
178
|
+
Marks the specified notification (by index or element) as read if it was unread, updating the unread count.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
#### `remove(index: number)`
|
|
183
|
+
|
|
184
|
+
Removes the notification at the given index, triggering any removal animations or cleanup.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
#### `clear()`
|
|
189
|
+
|
|
190
|
+
Safely clears all notifications from the list, removing them one by one, handling animations properly.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
### 🔔 Notification Center Visibility Controls
|
|
195
|
+
|
|
196
|
+
#### `open()`
|
|
197
|
+
|
|
198
|
+
Opens the notification center by showing the overlay and adding the `open` class.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
#### `close()`
|
|
203
|
+
|
|
204
|
+
Closes the notification center by hiding the overlay and removing the `open` class.
|
|
205
|
+
|
|
206
|
+
If `markAllAsReadOnClose` is enabled, marks all unread notifications as read on close.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
#### `toggle()`
|
|
211
|
+
|
|
212
|
+
Toggles the notification center open or closed based on current state.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
### 🔢 Count Management
|
|
217
|
+
|
|
218
|
+
#### `recount()`
|
|
219
|
+
|
|
220
|
+
Recalculates the number of unread notifications by counting `.item.unread` elements in the DOM list, updating the badge count.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
#### `get count() : number`
|
|
225
|
+
|
|
226
|
+
Returns the current number of unread notifications tracked internally.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### ➕ `add(message, mode = 'text')`
|
|
231
|
+
|
|
232
|
+
Adds a new notification to the notification center. 🎉
|
|
233
|
+
|
|
234
|
+
**Parameters:**
|
|
235
|
+
|
|
236
|
+
* `message` (`NotifyData`):
|
|
237
|
+
Can be either a simple string or an object containing:
|
|
238
|
+
|
|
239
|
+
* `title` (optional): notification title 📝
|
|
240
|
+
* `message`: main notification text or HTML content
|
|
241
|
+
* `avatar` (optional): URL for an avatar image 🖼️
|
|
242
|
+
* `onClick` (optional): callback function triggered when the notification is clicked 🎯
|
|
243
|
+
|
|
244
|
+
* `mode` (`'text' | 'html'`, default `'text'`):
|
|
245
|
+
Determines if the message content should be treated as plain text or HTML.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
**How it works:**
|
|
250
|
+
|
|
251
|
+
1. Creates a new `.item.unread` div to hold the notification.
|
|
252
|
+
|
|
253
|
+
2. If `message` is an object, it extracts the title, message, avatar URL, and click callback.
|
|
254
|
+
Otherwise, treats `message` as plain text content.
|
|
255
|
+
|
|
256
|
+
3. If an avatar URL is provided, creates a `.avatar` div with the avatar image as background.
|
|
257
|
+
|
|
258
|
+
4. Creates a `.content` wrapper containing:
|
|
259
|
+
|
|
260
|
+
* An optional `.title` element if a title exists
|
|
261
|
+
* A `.message` element containing the message, rendered as text or HTML depending on `mode`
|
|
262
|
+
|
|
263
|
+
5. If `onClick` callback is provided, marks the item `.clickable` and adds a click event listener that triggers the callback — but **prevents clicks on the close button** from triggering it.
|
|
264
|
+
|
|
265
|
+
6. Adds a close button (`×`) `.notify-close` inside the notification:
|
|
266
|
+
Clicking it removes the notification, stopping event propagation to avoid triggering the main click callback.
|
|
267
|
+
|
|
268
|
+
7. Prepends the notification to the top of the list, stores its mode, and updates the unread count.
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
**In short:**
|
|
273
|
+
You create a rich notification element dynamically, with optional avatar, title, content (text or HTML), clickable actions, and a close button — all neatly wired up! 🚀
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 🎨 CSS Files Location
|
|
278
|
+
|
|
279
|
+
The CSS files for the TinyNotify project build can be found in the following folder:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
dist/v1/css
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Inside this folder, you'll find the main stylesheets:
|
|
286
|
+
|
|
287
|
+
- `TinyNotify.css` — the full, unminified CSS file
|
|
288
|
+
- `TinyNotify.min.css` — the minified, optimized CSS file for production 🚀
|
|
289
|
+
|
|
290
|
+
Use these files to style your notifications!
|
|
291
|
+
Happy coding! ✨
|