core&ui: contest balloon notice (#1071)

This commit is contained in:
undefined authored and GitHub committed 2025-10-30 17:57:28 +00:00
1 parent 6d2442c6a3
commit 053978d9d4
12 files changed
+135 -63

No files matched your search

@@ -9,17 +9,22 @@ import { i18n, tpl } from 'vj/utils';
import Sock from '../socket';
let previous: VjNotification;
const onmessage = (msg) => {
console.log('Received message', msg);
const processI18n = (msg) => {
if (msg.mdoc.flag & FLAG_I18N) {
try {
msg.mdoc.content = JSON.parse(msg.mdoc.content);
if (msg.mdoc.content.url) msg.mdoc.url = msg.mdoc.content.url;
if (msg.mdoc.content.avatar) msg.mdoc.avatar = msg.mdoc.content.avatar;
msg.mdoc.content = i18n(msg.mdoc.content.message, ...msg.mdoc.content.params);
} catch (e) {
msg.mdoc.content = i18n(msg.mdoc.content);
}
}
return msg;
};
const onmessage = (msg) => {
console.log('Received message', msg);
msg = processI18n(msg);
if (msg.mdoc.flag & FLAG_ALERT) {
// Is alert
new InfoDialog({
@@ -48,6 +53,7 @@ const onmessage = (msg) => {
? {
type: 'info',
message: msg.mdoc.flag & FLAG_RICHTEXT ? i18n('You received a system message, click here to view.') : msg.mdoc.content,
...(msg.mdoc.avatar ? { avatar: msg.mdoc.avatar } : {}),
} : {
title: msg.udoc.uname,
avatar: msg.udoc.avatarUrl,
@@ -72,6 +78,8 @@ const initWorkerMode = (endpoint) => {
const { payload, type } = message.data;
if (type === 'message') {
if (onmessage(payload)) worker.port.postMessage({ type: 'ack', id: payload.mdoc._id });
} else if (type === 'i18n') {
worker.port.postMessage({ type: 'ack', id: `${payload.mdoc._id}-i18n`, payload: processI18n(payload) });
} else if (type === 'open-page') {
console.log('opening page');
window.open('/home/messages');
@@ -1,7 +1,7 @@
/// <reference no-default-lib="true" />
/// <reference lib="webworker" />
import ReconnectingWebsocket from 'reconnecting-websocket';
import { FLAG_INFO } from 'vj/constant/message';
import { FLAG_I18N, FLAG_INFO } from 'vj/constant/message';
declare const self: SharedWorkerGlobalScope;
console.log('SharedWorker init');
@@ -17,6 +17,7 @@ interface RequestInitSharedConnPayload {
interface RequestAckPayload {
type: 'ack';
id: string;
payload?: any;
}
interface RequestUnloadPayload {
type: 'unload';
@@ -28,28 +29,37 @@ function broadcastMsg(message: any) {
for (const p of ports) p.postMessage(message);
}
function onMessage(payload: any) {
broadcastMsg({ type: 'message', payload });
function onMessage(message: any) {
broadcastMsg({ type: 'message', payload: message });
let acked = false;
ack[payload.mdoc._id] = () => { acked = true; };
let payload = message;
ack[message.mdoc._id] = () => { acked = true; };
ack[`${message.mdoc._id}-i18n`] = (v) => { payload = v; };
if (message.mdoc.flag & FLAG_I18N) broadcastMsg({ type: 'i18n', payload: message });
setTimeout(() => {
delete ack[payload.mdoc._id];
delete ack[message.mdoc._id];
delete ack[`${message.mdoc._id}-i18n`];
if (acked) return;
if (payload.mdoc.flag & FLAG_INFO) return;
if (message.mdoc.flag & FLAG_INFO) return;
if (Notification?.permission !== 'granted') {
console.log('Notification permission denied');
return;
}
console.log('Sending as system notification');
// eslint-disable-next-line no-new
new Notification(
payload.udoc.uname || 'Hydro Notification',
{
payload.udoc._id === 1 ? payload.mdoc.content.split('\n')[0] : payload.udoc.uname || 'Hydro Notification',
payload.udoc._id === 1 ? {
tag: `notification-${payload.mdoc._id}`,
icon: payload.mdoc.avatar || '/android-chrome-192x192.png',
body: payload.mdoc.content.split('\n').slice(1).join('\n'),
} : {
tag: `message-${payload.mdoc._id}`,
icon: payload.udoc.avatarUrl || '/android-chrome-192x192.png',
body: payload.mdoc.content,
},
);
}, 5000);
}, 3000);
}
function initConn(path: string, port: MessagePort, cookie: any) {
@@ -92,7 +102,7 @@ self.onconnect = function (e) {
port.addEventListener('message', (msg: { data: RequestPayload }) => {
if (msg.data.type === 'conn') initConn(msg.data.path, port, msg.data.cookie);
if (msg.data.type === 'ack') ack[msg.data.id]?.();
if (msg.data.type === 'ack') ack[msg.data.id]?.(msg.data.payload);
if (msg.data.type === 'unload') ports.delete(port);
});
@@ -38,11 +38,12 @@ export default class Notification {
if (avatar) this.type += ' avatar';
if (title) this.type += ' title';
this.action = action || (() => { });
this.$dom = $(tpl`<div class="notification ${type} hide"></div>`);
if (avatar) $(tpl`<img width="64" height="64" class="avatar" src="${avatar}"></img>`).appendTo(this.$dom);
this.$dom = $(tpl`<div class="notification ${this.type} hide"></div>`);
if (avatar) $(tpl`<img width="32" height="32" class="avatar" src="${avatar}"></img>`).appendTo(this.$dom);
const content = message.split('\n').map((line) => tpl`<p>${line}</p>`).join('');
if (title) {
$(tpl`<div class="notification-content"><h2>${title}</h2><p>${message}</p></div>`).appendTo(this.$dom);
} else $(tpl`<p>${message}</p>`).appendTo(this.$dom);
$(tpl`<div class="notification-content"><h2>${title}</h2>${{ templateRaw: true, html: content }}</div>`).appendTo(this.$dom);
} else $(`<div>${content}</div>`).appendTo(this.$dom);
this.$dom.on('click', this.handleClick.bind(this));
this.$n = this.$dom
.css('z-index', zIndexManager.getNext())
@@ -21,6 +21,15 @@
opacity: 0
transform: translateY(20px) scale(0.9)
&.avatar
display: flex
align-items: center
.avatar
display: inline-block
vertical-align: top
margin-right: rem(10px)
&:before
display: inline-block
font-family: $icon-font-name !important
@@ -30,6 +39,9 @@
vertical-align: top
margin-top: rem((20px - $font-size-icon) / 2)
&.avatar:before
display: none !important
for key, value in $notification-color
&.{key}
border-left: 5px solid value
@@ -37,7 +49,7 @@
color: value
for key, value in $notification-icon
&.{key}:before
&:not(.avatar).{key}:before
content: value
+mobile()