From fdc7465d5566cdd1ca67169c6ae601530ea20e08 Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Wed, 6 Aug 2025 10:46:29 +0000
Subject: [PATCH 1/6] Add a configurable position for the esx_notify
---
[core]/esx_notify/Config.lua | 3 +-
[core]/esx_notify/Notify.lua | 3 +-
[core]/esx_notify/nui/css/style.css | 393 +++++++++++++++++++---------
[core]/esx_notify/nui/js/script.js | 280 ++++++++++----------
4 files changed, 413 insertions(+), 266 deletions(-)
diff --git a/[core]/esx_notify/Config.lua b/[core]/esx_notify/Config.lua
index 90f6d653..21b40d59 100644
--- a/[core]/esx_notify/Config.lua
+++ b/[core]/esx_notify/Config.lua
@@ -1,3 +1,4 @@
Config = {}
-Config.notificationSoundEnabled = true
\ No newline at end of file
+Config.notificationSoundEnabled = true
+Config.position = "middle-right" -- top-right, top-left, top-middle, bottom-right, bottom-left, bottom-middle, middle-left, middle-right
\ No newline at end of file
diff --git a/[core]/esx_notify/Notify.lua b/[core]/esx_notify/Notify.lua
index 0061974e..54bf75e5 100644
--- a/[core]/esx_notify/Notify.lua
+++ b/[core]/esx_notify/Notify.lua
@@ -37,7 +37,8 @@ local function Notify(notificatonType, length, message, title)
length = length or 5000,
message = message or "ESX-Notify",
title = title or "New Notification",
- notificationSoundEnabled = Config.notificationSoundEnabled
+ position = Config.position or "middle-right",
+ notificationSoundEnabled = Config.notificationSoundEnabled or false
}))
end
diff --git a/[core]/esx_notify/nui/css/style.css b/[core]/esx_notify/nui/css/style.css
index acb1b142..d53fe09b 100644
--- a/[core]/esx_notify/nui/css/style.css
+++ b/[core]/esx_notify/nui/css/style.css
@@ -1,196 +1,337 @@
-@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap");
+@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap');
:root {
- --background: rgba(20, 20, 20, 0.9);
- --text-color: #ffffff;
- --text-secondary: rgba(255, 255, 255, 0.7);
- --success-color: #2ecc71;
- --success-border: #1f9c4d;
- --error-color: #e74c3c;
- --error-border: #c0392b;
- --info-color: #3498db;
- --info-border: #2980b9;
- --warning-color: #f39c12;
- --warning-border: #d35400;
+ --background: rgba(20, 20, 20, 0.9);
+ --text-color: #ffffff;
+ --text-secondary: rgba(255, 255, 255, 0.7);
+ --success-color: #2ecc71;
+ --success-border: #1f9c4d;
+ --error-color: #e74c3c;
+ --error-border: #c0392b;
+ --info-color: #3498db;
+ --info-border: #2980b9;
+ --warning-color: #f39c12;
+ --warning-border: #d35400;
}
* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
}
body {
- width: 100vw;
- height: 100vh;
- font-family: "Poppins", sans-serif;
- overflow: hidden;
+ width: 100vw;
+ height: 100vh;
+ font-family: 'Poppins', sans-serif;
+ overflow: hidden;
}
#root {
- position: fixed;
- right: 2rem;
- top: 50%;
- transform: translateY(-50%);
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 10px;
- max-height: 80vh;
- z-index: 1000;
+ position: fixed;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 10px;
+ max-height: 80vh;
+ z-index: 1000;
+}
+
+#root.middle-right {
+ right: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+#root.middle-left {
+ left: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+#root.top-right {
+ right: 2rem;
+ top: 2rem;
+}
+
+#root.top-left {
+ left: 2rem;
+ top: 2rem;
+}
+
+#root.top-middle {
+ left: 50%;
+ top: 2rem;
+ transform: translateX(-50%);
+}
+
+#root.bottom-right {
+ right: 2rem;
+ bottom: 2rem;
+}
+
+#root.bottom-left {
+ left: 2rem;
+ bottom: 2rem;
+}
+
+#root.bottom-middle {
+ left: 50%;
+ bottom: 2rem;
+ transform: translateX(-50%);
}
.notify {
- display: flex;
- width: 300px;
- background: var(--background);
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- position: relative;
- padding: 12px;
- align-items: center;
- border-left: 4px solid #555;
+ display: flex;
+ width: 300px;
+ background: var(--background);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ position: relative;
+ padding: 12px;
+ align-items: center;
+ border-left: 4px solid #555;
}
.notify-success {
- border-left-color: var(--success-border);
+ border-left-color: var(--success-border);
}
.notify-error {
- border-left-color: var(--error-border);
+ border-left-color: var(--error-border);
}
.notify-info {
- border-left-color: var(--info-border);
+ border-left-color: var(--info-border);
}
.notify-warning {
- border-left-color: var(--warning-border);
+ border-left-color: var(--warning-border);
}
.notify-icon-container {
- margin-right: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
+ margin-right: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.hexagon {
- position: relative;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+ position: relative;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.hexagon::before {
- content: "";
- position: absolute;
- top: 3px;
- left: 3px;
- right: 3px;
- bottom: 3px;
- background: var(--background);
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 1;
+ content: '';
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ right: 3px;
+ bottom: 3px;
+ background: var(--background);
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 1;
}
.hexagon::after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
- opacity: 0.4;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 2;
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
+ opacity: 0.4;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 2;
}
.hexagon .material-symbols-outlined {
- color: var(--icon-color);
- font-size: 20px;
- position: relative;
- z-index: 3;
- filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
- display: flex;
- align-items: center;
- justify-content: center;
- height: 24px;
- width: 24px;
- margin-top: -1px;
+ color: var(--icon-color);
+ font-size: 20px;
+ position: relative;
+ z-index: 3;
+ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 24px;
+ width: 24px;
+ margin-top: -1px;
}
.notify-content {
- flex: 1;
- position: relative;
- padding-bottom: 8px;
+ flex: 1;
+ position: relative;
+ padding-bottom: 8px;
}
.notify-title {
- color: var(--text-color);
- font-size: 14px;
- font-weight: 600;
- margin-bottom: 2px;
+ color: var(--text-color);
+ font-size: 14px;
+ font-weight: 600;
+ margin-bottom: 2px;
}
.notify-text {
- color: var(--text-secondary);
- font-size: 12px;
- font-weight: 400;
+ color: var(--text-secondary);
+ font-size: 12px;
+ font-weight: 400;
}
.notify-progress {
- position: absolute;
- bottom: 0;
- left: 0;
- height: 2px;
- width: 100%;
- border-radius: 1px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ height: 2px;
+ width: 100%;
+ border-radius: 1px;
}
.material-symbols-outlined {
- font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 48;
+ font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 48;
}
.notify-warning .material-symbols-outlined,
.notify-error .material-symbols-outlined {
- margin-top: -2px;
+ margin-top: -2px;
}
-.fadeIn {
- animation: fadeIn 0.3s ease-in-out;
+#root.top-right .fadeIn,
+#root.bottom-right .fadeIn,
+#root.middle-right .fadeIn {
+ animation: fadeIn-right 0.3s ease-in-out;
+}
+
+#root.top-left .fadeIn,
+#root.bottom-left .fadeIn,
+#root.middle-left .fadeIn {
+ animation: fadeIn-left 0.3s ease-in-out;
+}
+
+#root.top-middle .fadeIn {
+ animation: fadeIn-top 0.3s ease-in-out;
+}
+
+#root.bottom-middle .fadeIn {
+ animation: fadeIn-bottom 0.3s ease-in-out;
}
.fadeOut {
- animation: fadeOut 0.5s ease-in-out;
- opacity: 0;
+ opacity: 0;
}
-@keyframes fadeIn {
- from {
- opacity: 0;
- transform: translateX(50px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
+#root.top-right .fadeOut,
+#root.bottom-right .fadeOut,
+#root.middle-right .fadeOut {
+ animation: fadeOut-right 0.5s ease-in-out;
}
-@keyframes fadeOut {
- from {
- opacity: 1;
- transform: translateX(0);
- }
- to {
- opacity: 0;
- transform: translateX(50px);
- }
+#root.top-left .fadeOut,
+#root.bottom-left .fadeOut,
+#root.middle-left .fadeOut {
+ animation: fadeOut-left 0.5s ease-in-out;
+}
+
+#root.top-middle .fadeOut {
+ animation: fadeOut-top 0.5s ease-in-out;
+}
+#root.bottom-middle .fadeOut {
+ animation: fadeOut-bottom 0.5s ease-in-out;
+}
+
+@keyframes fadeIn-right {
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes fadeIn-left {
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
+}
+
+@keyframes fadeIn-top {
+ from {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeIn-bottom {
+ from {
+ opacity: 0;
+ transform: translateY(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+@keyframes fadeOut-right {
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+}
+
+@keyframes fadeOut-left {
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+}
+
+@keyframes fadeOut-top {
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
+}
+
+@keyframes fadeOut-bottom {
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(50px);
+ }
}
diff --git a/[core]/esx_notify/nui/js/script.js b/[core]/esx_notify/nui/js/script.js
index 1152ed14..c66f882f 100644
--- a/[core]/esx_notify/nui/js/script.js
+++ b/[core]/esx_notify/nui/js/script.js
@@ -1,160 +1,165 @@
-const w = window
+const w = window;
const types = {
- ["success"]: {
- ["icon"]: "check_circle",
- ["frequency"]: 800,
- ["duration"]: 100,
- ["color"]: "#2ecc71",
- ["borderColor"]: "#1f9c4d",
- },
- ["error"]: {
- ["icon"]: "error",
- ["frequency"]: 300,
- ["duration"]: 150,
- ["color"]: "#e74c3c",
- ["borderColor"]: "#c0392b",
- },
- ["info"]: {
- ["icon"]: "info",
- ["frequency"]: 600,
- ["duration"]: 100,
- ["color"]: "#3498db",
- ["borderColor"]: "#2980b9",
- },
- ["warning"]: {
- ["icon"]: "warning_amber",
- ["frequency"]: 450,
- ["duration"]: 125,
- ["color"]: "#f39c12",
- ["borderColor"]: "#d35400",
- },
-}
+ ['success']: {
+ ['icon']: 'check_circle',
+ ['frequency']: 800,
+ ['duration']: 100,
+ ['color']: '#2ecc71',
+ ['borderColor']: '#1f9c4d',
+ },
+ ['error']: {
+ ['icon']: 'error',
+ ['frequency']: 300,
+ ['duration']: 150,
+ ['color']: '#e74c3c',
+ ['borderColor']: '#c0392b',
+ },
+ ['info']: {
+ ['icon']: 'info',
+ ['frequency']: 600,
+ ['duration']: 100,
+ ['color']: '#3498db',
+ ['borderColor']: '#2980b9',
+ },
+ ['warning']: {
+ ['icon']: 'warning_amber',
+ ['frequency']: 450,
+ ['duration']: 125,
+ ['color']: '#f39c12',
+ ['borderColor']: '#d35400',
+ },
+};
// the color codes example `i ~r~love~s~ donuts`
const codes = {
- "~r~": "#c0392b",
- "~b~": "#378cbf",
- "~g~": "#2ecc71",
- "~y~": "yellow",
- "~p~": "purple",
- "~c~": "grey",
- "~m~": "#212121",
- "~u~": "black",
- "~o~": "#fb9b04",
-}
+ '~r~': '#c0392b',
+ '~b~': '#378cbf',
+ '~g~': '#2ecc71',
+ '~y~': 'yellow',
+ '~p~': 'purple',
+ '~c~': 'grey',
+ '~m~': '#212121',
+ '~u~': 'black',
+ '~o~': '#fb9b04',
+};
// Audio context for sound effects
-let audioContext
+let audioContext;
// Initialize audio context on user interaction
-document.addEventListener("click", initAudioContext, { once: true })
-document.addEventListener("keydown", initAudioContext, { once: true })
+document.addEventListener('click', initAudioContext, { once: true });
+document.addEventListener('keydown', initAudioContext, { once: true });
function initAudioContext() {
- if (!audioContext) {
- audioContext = new (window.AudioContext || window.webkitAudioContext)()
- }
+ if (!audioContext) {
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
+ }
}
function playNotificationSound(type) {
- if (!audioContext) initAudioContext()
+ if (!audioContext) initAudioContext();
- const typeConfig = types[type] || types["info"]
- const oscillator = audioContext.createOscillator()
- const gainNode = audioContext.createGain()
+ const typeConfig = types[type] || types['info'];
+ const oscillator = audioContext.createOscillator();
+ const gainNode = audioContext.createGain();
- oscillator.type = "sine"
- oscillator.frequency.setValueAtTime(typeConfig.frequency, audioContext.currentTime)
+ oscillator.type = 'sine';
+ oscillator.frequency.setValueAtTime(typeConfig.frequency, audioContext.currentTime);
- gainNode.gain.setValueAtTime(0.3, audioContext.currentTime)
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + typeConfig.duration / 1000)
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + typeConfig.duration / 1000);
- oscillator.connect(gainNode)
- gainNode.connect(audioContext.destination)
+ oscillator.connect(gainNode);
+ gainNode.connect(audioContext.destination);
- oscillator.start()
- oscillator.stop(audioContext.currentTime + typeConfig.duration / 1000)
+ oscillator.start();
+ oscillator.stop(audioContext.currentTime + typeConfig.duration / 1000);
}
-w.addEventListener("message", (event) => {
- notification({
- type: event.data.type,
- title: event.data.title || "New Notification",
- message: event.data.message,
- length: event.data.length,
- notificationSoundEnabled: event.data.notificationSoundEnabled,
- })
-})
+w.addEventListener('message', (event) => {
+ notification({
+ type: event.data.type,
+ title: event.data.title || 'New Notification',
+ message: event.data.message,
+ length: event.data.length,
+ position: event.data.position,
+ notificationSoundEnabled: event.data.notificationSoundEnabled,
+ });
+});
const replaceColors = (str, obj) => {
- let strToReplace = str
+ let strToReplace = str;
- for (const id in obj) {
- strToReplace = strToReplace.replace(new RegExp(id, "g"), obj[id])
- }
+ for (const id in obj) {
+ strToReplace = strToReplace.replace(new RegExp(id, 'g'), obj[id]);
+ }
- return strToReplace
-}
+ return strToReplace;
+};
const sanitizeHTML = (str) => {
- const temp = document.createElement("div")
- temp.textContent = str
- return temp.innerHTML
-}
+ const temp = document.createElement('div');
+ temp.textContent = str;
+ return temp.innerHTML;
+};
const processLineBreaks = (str) => {
- // Replace
tags with actual line breaks
- return str.replace(/<br>/g, "
")
-}
+ // Replace
tags with actual line breaks
+ return str.replace(/<br>/g, '
');
+};
const notification = (data) => {
- if (typeof $ === "undefined") {
- console.error("jQuery is not loaded. Please ensure jQuery is included in your project.")
- return
- }
+ if (typeof $ === 'undefined') {
+ console.error('jQuery is not loaded. Please ensure jQuery is included in your project.');
+ return;
+ }
- if (data.message) {
- // Remove any standalone ~s~ tags (not preceded by a color code)
- data.message = data.message.replace(/~s~/g, "")
- }
+ if (data.message) {
+ // Remove any standalone ~s~ tags (not preceded by a color code)
+ data.message = data.message.replace(/~s~/g, '');
+ }
- if (data.title) {
- // Remove any standalone ~s~ tags (not preceded by a color code)
- data.title = data.title.replace(/~s~/g, "")
- }
+ if (data.title) {
+ // Remove any standalone ~s~ tags (not preceded by a color code)
+ data.title = data.title.replace(/~s~/g, '');
+ }
- let sanitizedTitle = data.title ? sanitizeHTML(data.title) : ""
- let sanitizedMessage = data.message ? sanitizeHTML(data.message) : ""
+ let sanitizedTitle = data.title ? sanitizeHTML(data.title) : '';
+ let sanitizedMessage = data.message ? sanitizeHTML(data.message) : '';
- if (data.title) {
- for (const color in codes) {
- if (sanitizedTitle.includes(color)) {
- const objArr = {}
- objArr[color] = ``
- objArr["~s~"] = ""
- sanitizedTitle = replaceColors(sanitizedTitle, objArr)
- }
- }
- }
+ if (data.title) {
+ for (const color in codes) {
+ if (sanitizedTitle.includes(color)) {
+ const objArr = {};
+ objArr[color] = ``;
+ objArr['~s~'] = '';
+ sanitizedTitle = replaceColors(sanitizedTitle, objArr);
+ }
+ }
+ }
- for (const color in codes) {
- if (sanitizedMessage.includes(color)) {
- const objArr = {}
- objArr[color] = ``
- objArr["~s~"] = ""
- sanitizedMessage = replaceColors(sanitizedMessage, objArr)
- }
- }
+ for (const color in codes) {
+ if (sanitizedMessage.includes(color)) {
+ const objArr = {};
+ objArr[color] = ``;
+ objArr['~s~'] = '';
+ sanitizedMessage = replaceColors(sanitizedMessage, objArr);
+ }
+ }
- sanitizedMessage = processLineBreaks(sanitizedMessage)
- sanitizedTitle = processLineBreaks(sanitizedTitle)
+ sanitizedMessage = processLineBreaks(sanitizedMessage);
+ sanitizedTitle = processLineBreaks(sanitizedTitle);
- const id = Math.floor(Math.random() * 100000)
- const typeInfo = types[data.type] || types["info"]
- const duration = data.length || 3000
+ const id = Math.floor(Math.random() * 100000);
+ const typeInfo = types[data.type] || types['info'];
+ const duration = data.length || 3000;
- const notificationElement = $(`
+ $('#root')
+ .removeClass()
+ .addClass(data.position || 'middle-right');
+
+ const notificationElement = $(`
@@ -167,28 +172,27 @@ const notification = (data) => {
- `).appendTo(`#root`)
+ `).appendTo(`#root`);
- $(`#${id} .notify-progress`).css({
- transition: `width ${duration}ms linear`,
- width: "0%",
- })
+ $(`#${id} .notify-progress`).css({
+ transition: `width ${duration}ms linear`,
+ width: '0%',
+ });
- if (data.notificationSoundEnabled) {
- playNotificationSound(data.type)
- }
-
+ if (data.notificationSoundEnabled) {
+ playNotificationSound(data.type);
+ }
- setTimeout(() => {
- $(`#${id} .notify-progress`).css("width", "100%")
- }, 10)
+ setTimeout(() => {
+ $(`#${id} .notify-progress`).css('width', '100%');
+ }, 10);
- setTimeout(() => {
- $(`#${id}`).removeClass("fadeIn").addClass("fadeOut")
- setTimeout(() => {
- $(`#${id}`).remove()
- }, 500)
- }, duration)
+ setTimeout(() => {
+ $(`#${id}`).removeClass('fadeIn').addClass('fadeOut');
+ setTimeout(() => {
+ $(`#${id}`).remove();
+ }, 500);
+ }, duration);
- return notificationElement
-}
+ return notificationElement;
+};
From 429cc9337af75125d060f58adb384b24fc1ee210 Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Wed, 6 Aug 2025 11:03:49 +0000
Subject: [PATCH 2/6] Change tab space and ' to "
---
[core]/esx_notify/nui/css/style.css | 388 ++++++++++++++--------------
[core]/esx_notify/nui/js/script.js | 262 +++++++++----------
2 files changed, 325 insertions(+), 325 deletions(-)
diff --git a/[core]/esx_notify/nui/css/style.css b/[core]/esx_notify/nui/css/style.css
index d53fe09b..30ff7495 100644
--- a/[core]/esx_notify/nui/css/style.css
+++ b/[core]/esx_notify/nui/css/style.css
@@ -1,337 +1,337 @@
-@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap');
+@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap");
:root {
- --background: rgba(20, 20, 20, 0.9);
- --text-color: #ffffff;
- --text-secondary: rgba(255, 255, 255, 0.7);
- --success-color: #2ecc71;
- --success-border: #1f9c4d;
- --error-color: #e74c3c;
- --error-border: #c0392b;
- --info-color: #3498db;
- --info-border: #2980b9;
- --warning-color: #f39c12;
- --warning-border: #d35400;
+ --background: rgba(20, 20, 20, 0.9);
+ --text-color: #ffffff;
+ --text-secondary: rgba(255, 255, 255, 0.7);
+ --success-color: #2ecc71;
+ --success-border: #1f9c4d;
+ --error-color: #e74c3c;
+ --error-border: #c0392b;
+ --info-color: #3498db;
+ --info-border: #2980b9;
+ --warning-color: #f39c12;
+ --warning-border: #d35400;
}
* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
}
body {
- width: 100vw;
- height: 100vh;
- font-family: 'Poppins', sans-serif;
- overflow: hidden;
+ width: 100vw;
+ height: 100vh;
+ font-family: "Poppins", sans-serif;
+ overflow: hidden;
}
#root {
- position: fixed;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 10px;
- max-height: 80vh;
- z-index: 1000;
+ position: fixed;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 10px;
+ max-height: 80vh;
+ z-index: 1000;
}
#root.middle-right {
- right: 2rem;
- top: 50%;
- transform: translateY(-50%);
+ right: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
}
#root.middle-left {
- left: 2rem;
- top: 50%;
- transform: translateY(-50%);
+ left: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
}
#root.top-right {
- right: 2rem;
- top: 2rem;
+ right: 2rem;
+ top: 2rem;
}
#root.top-left {
- left: 2rem;
- top: 2rem;
+ left: 2rem;
+ top: 2rem;
}
#root.top-middle {
- left: 50%;
- top: 2rem;
- transform: translateX(-50%);
+ left: 50%;
+ top: 2rem;
+ transform: translateX(-50%);
}
#root.bottom-right {
- right: 2rem;
- bottom: 2rem;
+ right: 2rem;
+ bottom: 2rem;
}
#root.bottom-left {
- left: 2rem;
- bottom: 2rem;
+ left: 2rem;
+ bottom: 2rem;
}
#root.bottom-middle {
- left: 50%;
- bottom: 2rem;
- transform: translateX(-50%);
+ left: 50%;
+ bottom: 2rem;
+ transform: translateX(-50%);
}
.notify {
- display: flex;
- width: 300px;
- background: var(--background);
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- position: relative;
- padding: 12px;
- align-items: center;
- border-left: 4px solid #555;
+ display: flex;
+ width: 300px;
+ background: var(--background);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ position: relative;
+ padding: 12px;
+ align-items: center;
+ border-left: 4px solid #555;
}
.notify-success {
- border-left-color: var(--success-border);
+ border-left-color: var(--success-border);
}
.notify-error {
- border-left-color: var(--error-border);
+ border-left-color: var(--error-border);
}
.notify-info {
- border-left-color: var(--info-border);
+ border-left-color: var(--info-border);
}
.notify-warning {
- border-left-color: var(--warning-border);
+ border-left-color: var(--warning-border);
}
.notify-icon-container {
- margin-right: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
+ margin-right: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.hexagon {
- position: relative;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+ position: relative;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.hexagon::before {
- content: '';
- position: absolute;
- top: 3px;
- left: 3px;
- right: 3px;
- bottom: 3px;
- background: var(--background);
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 1;
+ content: "";
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ right: 3px;
+ bottom: 3px;
+ background: var(--background);
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 1;
}
.hexagon::after {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
- opacity: 0.4;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 2;
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
+ opacity: 0.4;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 2;
}
.hexagon .material-symbols-outlined {
- color: var(--icon-color);
- font-size: 20px;
- position: relative;
- z-index: 3;
- filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
- display: flex;
- align-items: center;
- justify-content: center;
- height: 24px;
- width: 24px;
- margin-top: -1px;
+ color: var(--icon-color);
+ font-size: 20px;
+ position: relative;
+ z-index: 3;
+ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 24px;
+ width: 24px;
+ margin-top: -1px;
}
.notify-content {
- flex: 1;
- position: relative;
- padding-bottom: 8px;
+ flex: 1;
+ position: relative;
+ padding-bottom: 8px;
}
.notify-title {
- color: var(--text-color);
- font-size: 14px;
- font-weight: 600;
- margin-bottom: 2px;
+ color: var(--text-color);
+ font-size: 14px;
+ font-weight: 600;
+ margin-bottom: 2px;
}
.notify-text {
- color: var(--text-secondary);
- font-size: 12px;
- font-weight: 400;
+ color: var(--text-secondary);
+ font-size: 12px;
+ font-weight: 400;
}
.notify-progress {
- position: absolute;
- bottom: 0;
- left: 0;
- height: 2px;
- width: 100%;
- border-radius: 1px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ height: 2px;
+ width: 100%;
+ border-radius: 1px;
}
.material-symbols-outlined {
- font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 48;
+ font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 48;
}
.notify-warning .material-symbols-outlined,
.notify-error .material-symbols-outlined {
- margin-top: -2px;
+ margin-top: -2px;
}
#root.top-right .fadeIn,
#root.bottom-right .fadeIn,
#root.middle-right .fadeIn {
- animation: fadeIn-right 0.3s ease-in-out;
+ animation: fadeIn-right 0.3s ease-in-out;
}
#root.top-left .fadeIn,
#root.bottom-left .fadeIn,
#root.middle-left .fadeIn {
- animation: fadeIn-left 0.3s ease-in-out;
+ animation: fadeIn-left 0.3s ease-in-out;
}
#root.top-middle .fadeIn {
- animation: fadeIn-top 0.3s ease-in-out;
+ animation: fadeIn-top 0.3s ease-in-out;
}
#root.bottom-middle .fadeIn {
- animation: fadeIn-bottom 0.3s ease-in-out;
+ animation: fadeIn-bottom 0.3s ease-in-out;
}
.fadeOut {
- opacity: 0;
+ opacity: 0;
}
#root.top-right .fadeOut,
#root.bottom-right .fadeOut,
#root.middle-right .fadeOut {
- animation: fadeOut-right 0.5s ease-in-out;
+ animation: fadeOut-right 0.5s ease-in-out;
}
#root.top-left .fadeOut,
#root.bottom-left .fadeOut,
#root.middle-left .fadeOut {
- animation: fadeOut-left 0.5s ease-in-out;
+ animation: fadeOut-left 0.5s ease-in-out;
}
#root.top-middle .fadeOut {
- animation: fadeOut-top 0.5s ease-in-out;
+ animation: fadeOut-top 0.5s ease-in-out;
}
#root.bottom-middle .fadeOut {
- animation: fadeOut-bottom 0.5s ease-in-out;
+ animation: fadeOut-bottom 0.5s ease-in-out;
}
@keyframes fadeIn-right {
- from {
- opacity: 0;
- transform: translateX(50px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
}
@keyframes fadeIn-left {
- from {
- opacity: 0;
- transform: translateX(-50px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
}
@keyframes fadeIn-top {
- from {
- opacity: 0;
- transform: translateY(-50px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
+ from {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
@keyframes fadeIn-bottom {
- from {
- opacity: 0;
- transform: translateY(50px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
+ from {
+ opacity: 0;
+ transform: translateY(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
@keyframes fadeOut-right {
- from {
- opacity: 1;
- transform: translateX(0);
- }
- to {
- opacity: 0;
- transform: translateX(50px);
- }
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(50px);
+ }
}
@keyframes fadeOut-left {
- from {
- opacity: 1;
- transform: translateX(0);
- }
- to {
- opacity: 0;
- transform: translateX(-50px);
- }
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
}
@keyframes fadeOut-top {
- from {
- opacity: 1;
- transform: translateY(0);
- }
- to {
- opacity: 0;
- transform: translateY(-50px);
- }
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
}
@keyframes fadeOut-bottom {
- from {
- opacity: 1;
- transform: translateY(0);
- }
- to {
- opacity: 0;
- transform: translateY(50px);
- }
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(50px);
+ }
}
diff --git a/[core]/esx_notify/nui/js/script.js b/[core]/esx_notify/nui/js/script.js
index c66f882f..3a1872e7 100644
--- a/[core]/esx_notify/nui/js/script.js
+++ b/[core]/esx_notify/nui/js/script.js
@@ -1,165 +1,165 @@
const w = window;
const types = {
- ['success']: {
- ['icon']: 'check_circle',
- ['frequency']: 800,
- ['duration']: 100,
- ['color']: '#2ecc71',
- ['borderColor']: '#1f9c4d',
- },
- ['error']: {
- ['icon']: 'error',
- ['frequency']: 300,
- ['duration']: 150,
- ['color']: '#e74c3c',
- ['borderColor']: '#c0392b',
- },
- ['info']: {
- ['icon']: 'info',
- ['frequency']: 600,
- ['duration']: 100,
- ['color']: '#3498db',
- ['borderColor']: '#2980b9',
- },
- ['warning']: {
- ['icon']: 'warning_amber',
- ['frequency']: 450,
- ['duration']: 125,
- ['color']: '#f39c12',
- ['borderColor']: '#d35400',
- },
+ ["success"]: {
+ ["icon"]: "check_circle",
+ ["frequency"]: 800,
+ ["duration"]: 100,
+ ["color"]: "#2ecc71",
+ ["borderColor"]: "#1f9c4d",
+ },
+ ["error"]: {
+ ["icon"]: "error",
+ ["frequency"]: 300,
+ ["duration"]: 150,
+ ["color"]: "#e74c3c",
+ ["borderColor"]: "#c0392b",
+ },
+ ["info"]: {
+ ["icon"]: "info",
+ ["frequency"]: 600,
+ ["duration"]: 100,
+ ["color"]: "#3498db",
+ ["borderColor"]: "#2980b9",
+ },
+ ["warning"]: {
+ ["icon"]: "warning_amber",
+ ["frequency"]: 450,
+ ["duration"]: 125,
+ ["color"]: "#f39c12",
+ ["borderColor"]: "#d35400",
+ },
};
// the color codes example `i ~r~love~s~ donuts`
const codes = {
- '~r~': '#c0392b',
- '~b~': '#378cbf',
- '~g~': '#2ecc71',
- '~y~': 'yellow',
- '~p~': 'purple',
- '~c~': 'grey',
- '~m~': '#212121',
- '~u~': 'black',
- '~o~': '#fb9b04',
+ "~r~": "#c0392b",
+ "~b~": "#378cbf",
+ "~g~": "#2ecc71",
+ "~y~": "yellow",
+ "~p~": "purple",
+ "~c~": "grey",
+ "~m~": "#212121",
+ "~u~": "black",
+ "~o~": "#fb9b04",
};
// Audio context for sound effects
let audioContext;
// Initialize audio context on user interaction
-document.addEventListener('click', initAudioContext, { once: true });
-document.addEventListener('keydown', initAudioContext, { once: true });
+document.addEventListener("click", initAudioContext, { once: true });
+document.addEventListener("keydown", initAudioContext, { once: true });
function initAudioContext() {
- if (!audioContext) {
- audioContext = new (window.AudioContext || window.webkitAudioContext)();
- }
+ if (!audioContext) {
+ audioContext = new (window.AudioContext || window.webkitAudioContext)();
+ }
}
function playNotificationSound(type) {
- if (!audioContext) initAudioContext();
+ if (!audioContext) initAudioContext();
- const typeConfig = types[type] || types['info'];
- const oscillator = audioContext.createOscillator();
- const gainNode = audioContext.createGain();
+ const typeConfig = types[type] || types["info"];
+ const oscillator = audioContext.createOscillator();
+ const gainNode = audioContext.createGain();
- oscillator.type = 'sine';
- oscillator.frequency.setValueAtTime(typeConfig.frequency, audioContext.currentTime);
+ oscillator.type = "sine";
+ oscillator.frequency.setValueAtTime(typeConfig.frequency, audioContext.currentTime);
- gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
- gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + typeConfig.duration / 1000);
+ gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + typeConfig.duration / 1000);
- oscillator.connect(gainNode);
- gainNode.connect(audioContext.destination);
+ oscillator.connect(gainNode);
+ gainNode.connect(audioContext.destination);
- oscillator.start();
- oscillator.stop(audioContext.currentTime + typeConfig.duration / 1000);
+ oscillator.start();
+ oscillator.stop(audioContext.currentTime + typeConfig.duration / 1000);
}
-w.addEventListener('message', (event) => {
- notification({
- type: event.data.type,
- title: event.data.title || 'New Notification',
- message: event.data.message,
- length: event.data.length,
- position: event.data.position,
- notificationSoundEnabled: event.data.notificationSoundEnabled,
- });
+w.addEventListener("message", (event) => {
+ notification({
+ type: event.data.type,
+ title: event.data.title || "New Notification",
+ message: event.data.message,
+ length: event.data.length,
+ position: event.data.position,
+ notificationSoundEnabled: event.data.notificationSoundEnabled,
+ });
});
const replaceColors = (str, obj) => {
- let strToReplace = str;
+ let strToReplace = str;
- for (const id in obj) {
- strToReplace = strToReplace.replace(new RegExp(id, 'g'), obj[id]);
- }
+ for (const id in obj) {
+ strToReplace = strToReplace.replace(new RegExp(id, "g"), obj[id]);
+ }
- return strToReplace;
+ return strToReplace;
};
const sanitizeHTML = (str) => {
- const temp = document.createElement('div');
- temp.textContent = str;
- return temp.innerHTML;
+ const temp = document.createElement("div");
+ temp.textContent = str;
+ return temp.innerHTML;
};
const processLineBreaks = (str) => {
- // Replace
tags with actual line breaks
- return str.replace(/<br>/g, '
');
+ // Replace
tags with actual line breaks
+ return str.replace(/<br>/g, "
");
};
const notification = (data) => {
- if (typeof $ === 'undefined') {
- console.error('jQuery is not loaded. Please ensure jQuery is included in your project.');
- return;
- }
+ if (typeof $ === "undefined") {
+ console.error("jQuery is not loaded. Please ensure jQuery is included in your project.");
+ return;
+ }
- if (data.message) {
- // Remove any standalone ~s~ tags (not preceded by a color code)
- data.message = data.message.replace(/~s~/g, '');
- }
+ if (data.message) {
+ // Remove any standalone ~s~ tags (not preceded by a color code)
+ data.message = data.message.replace(/~s~/g, "");
+ }
- if (data.title) {
- // Remove any standalone ~s~ tags (not preceded by a color code)
- data.title = data.title.replace(/~s~/g, '');
- }
+ if (data.title) {
+ // Remove any standalone ~s~ tags (not preceded by a color code)
+ data.title = data.title.replace(/~s~/g, "");
+ }
- let sanitizedTitle = data.title ? sanitizeHTML(data.title) : '';
- let sanitizedMessage = data.message ? sanitizeHTML(data.message) : '';
+ let sanitizedTitle = data.title ? sanitizeHTML(data.title) : "";
+ let sanitizedMessage = data.message ? sanitizeHTML(data.message) : "";
- if (data.title) {
- for (const color in codes) {
- if (sanitizedTitle.includes(color)) {
- const objArr = {};
- objArr[color] = `
`;
- objArr['~s~'] = '';
- sanitizedTitle = replaceColors(sanitizedTitle, objArr);
- }
- }
- }
+ if (data.title) {
+ for (const color in codes) {
+ if (sanitizedTitle.includes(color)) {
+ const objArr = {};
+ objArr[color] = `
`;
+ objArr["~s~"] = "";
+ sanitizedTitle = replaceColors(sanitizedTitle, objArr);
+ }
+ }
+ }
- for (const color in codes) {
- if (sanitizedMessage.includes(color)) {
- const objArr = {};
- objArr[color] = `
`;
- objArr['~s~'] = '';
- sanitizedMessage = replaceColors(sanitizedMessage, objArr);
- }
- }
+ for (const color in codes) {
+ if (sanitizedMessage.includes(color)) {
+ const objArr = {};
+ objArr[color] = `
`;
+ objArr["~s~"] = "";
+ sanitizedMessage = replaceColors(sanitizedMessage, objArr);
+ }
+ }
- sanitizedMessage = processLineBreaks(sanitizedMessage);
- sanitizedTitle = processLineBreaks(sanitizedTitle);
+ sanitizedMessage = processLineBreaks(sanitizedMessage);
+ sanitizedTitle = processLineBreaks(sanitizedTitle);
- const id = Math.floor(Math.random() * 100000);
- const typeInfo = types[data.type] || types['info'];
- const duration = data.length || 3000;
+ const id = Math.floor(Math.random() * 100000);
+ const typeInfo = types[data.type] || types["info"];
+ const duration = data.length || 3000;
- $('#root')
- .removeClass()
- .addClass(data.position || 'middle-right');
+ $("#root")
+ .removeClass()
+ .addClass(data.position || "middle-right");
- const notificationElement = $(`
+ const notificationElement = $(`
@@ -174,25 +174,25 @@ const notification = (data) => {
`).appendTo(`#root`);
- $(`#${id} .notify-progress`).css({
- transition: `width ${duration}ms linear`,
- width: '0%',
- });
+ $(`#${id} .notify-progress`).css({
+ transition: `width ${duration}ms linear`,
+ width: "0%",
+ });
- if (data.notificationSoundEnabled) {
- playNotificationSound(data.type);
- }
+ if (data.notificationSoundEnabled) {
+ playNotificationSound(data.type);
+ }
- setTimeout(() => {
- $(`#${id} .notify-progress`).css('width', '100%');
- }, 10);
+ setTimeout(() => {
+ $(`#${id} .notify-progress`).css("width", "100%");
+ }, 10);
- setTimeout(() => {
- $(`#${id}`).removeClass('fadeIn').addClass('fadeOut');
- setTimeout(() => {
- $(`#${id}`).remove();
- }, 500);
- }, duration);
+ setTimeout(() => {
+ $(`#${id}`).removeClass("fadeIn").addClass("fadeOut");
+ setTimeout(() => {
+ $(`#${id}`).remove();
+ }, 500);
+ }, duration);
- return notificationElement;
+ return notificationElement;
};
From 7cc6d88513f1d52453bfdcf41b781aeef48c1a8c Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Fri, 8 Aug 2025 10:00:59 +0000
Subject: [PATCH 3/6] Add position parameter and proper debug print
---
[core]/esx_notify/Notify.lua | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/[core]/esx_notify/Notify.lua b/[core]/esx_notify/Notify.lua
index 54bf75e5..54bc48c7 100644
--- a/[core]/esx_notify/Notify.lua
+++ b/[core]/esx_notify/Notify.lua
@@ -1,16 +1,28 @@
local Debug = ESX.GetConfig().EnableDebug
+local possiblePosition = {
+ ["top-right"] = true,
+ ["top-left"] = true,
+ ["top-middle"] = true,
+ ["bottom-right"] = true,
+ ["bottom-left"] = true,
+ ["bottom-middle"] = true,
+ ["middle-left"] = true,
+ ["middle-right"] = true
+}
---@param notificatonType string the notification type
---@param length number the length of the notification
---@param message any the message :D
---@param title string optional title for the notification
-local function Notify(notificatonType, length, message, title)
+---@param position string optional position for the notification
+local function Notify(notificatonType, length, message, title, position)
if Debug then
print("1 ".. tostring(notificatonType))
print("2 "..tostring(length))
print("3 "..message)
print("4 "..tostring(title))
+ print("5 "..tostring(position))
end
if type(notificatonType) ~= "string" then
@@ -21,11 +33,16 @@ local function Notify(notificatonType, length, message, title)
length = 3000
end
+ if not possiblePosition[position] then
+ position = Config.position or "middle-right"
+ end
+
if Debug then
- print("5 ".. tostring(notificatonType))
- print("6 "..tostring(length))
- print("7 "..message)
- print("8 "..tostring(title))
+ print("6 ".. tostring(notificatonType))
+ print("7 "..tostring(length))
+ print("8 "..message)
+ print("9 "..tostring(title))
+ print("10 "..tostring(position))
end
if type(message) == "string" then
@@ -37,7 +54,7 @@ local function Notify(notificatonType, length, message, title)
length = length or 5000,
message = message or "ESX-Notify",
title = title or "New Notification",
- position = Config.position or "middle-right",
+ position = position,
notificationSoundEnabled = Config.notificationSoundEnabled or false
}))
end
From 056b3393c5ccf4d2322d174e75f07c4ee0ecca0a Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Sat, 9 Aug 2025 13:39:43 +0000
Subject: [PATCH 4/6] add position argument to player class and
shownotification function
---
[core]/es_extended/client/functions.lua | 5 +++--
[core]/es_extended/server/classes/player.lua | 5 +++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/[core]/es_extended/client/functions.lua b/[core]/es_extended/client/functions.lua
index 32f8f5d9..f74e4688 100644
--- a/[core]/es_extended/client/functions.lua
+++ b/[core]/es_extended/client/functions.lua
@@ -153,9 +153,10 @@ end
---@param notifyType? string The type of notification to show
---@param length? number The length of the notification
---@param title? string The title of the notification
+---@param position? string The position of the notification
---@return nil
-function ESX.ShowNotification(message, notifyType, length, title)
- return IsResourceFound('esx_notify') and exports['esx_notify']:Notify(notifyType, length, message, title)
+function ESX.ShowNotification(message, notifyType, length, title, position)
+ return IsResourceFound('esx_notify') and exports['esx_notify']:Notify(notifyType, length, message, title, position)
end
function ESX.TextUI(...)
diff --git a/[core]/es_extended/server/classes/player.lua b/[core]/es_extended/server/classes/player.lua
index df1d1ee5..4a94d6d8 100644
--- a/[core]/es_extended/server/classes/player.lua
+++ b/[core]/es_extended/server/classes/player.lua
@@ -790,9 +790,10 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
---@param msg string
---@param notifyType string
---@param length number
+ ---@param position string
---@return nil
- function self.showNotification(msg, notifyType, length)
- self.triggerEvent("esx:showNotification", msg, notifyType, length)
+ function self.showNotification(msg, notifyType, length, position)
+ self.triggerEvent("esx:showNotification", msg, notifyType, length, position)
end
---@param sender string
From 02ecc1e822ed3b7fe25d95154faeb52a3bc7d1b4 Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Sat, 9 Aug 2025 17:48:51 +0000
Subject: [PATCH 5/6] add title before position argument in player class
---
[core]/es_extended/server/classes/player.lua | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/[core]/es_extended/server/classes/player.lua b/[core]/es_extended/server/classes/player.lua
index 4a94d6d8..0a22d3f1 100644
--- a/[core]/es_extended/server/classes/player.lua
+++ b/[core]/es_extended/server/classes/player.lua
@@ -790,10 +790,11 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory,
---@param msg string
---@param notifyType string
---@param length number
+ ---@param title string
---@param position string
---@return nil
- function self.showNotification(msg, notifyType, length, position)
- self.triggerEvent("esx:showNotification", msg, notifyType, length, position)
+ function self.showNotification(msg, notifyType, length, title, position)
+ self.triggerEvent("esx:showNotification", msg, notifyType, length, title, position)
end
---@param sender string
From 2009ccfd514e10682621045023c4b0616617af12 Mon Sep 17 00:00:00 2001
From: alexistb2904 <59259007+alexistb2904@users.noreply.github.com>
Date: Thu, 21 Aug 2025 19:23:03 +0000
Subject: [PATCH 6/6] Add possibility to trigger multiple notifications at
different positions. Update to the readme too.
---
[core]/esx_notify/Notify.lua | 4 +-
[core]/esx_notify/fxmanifest.lua | 2 +-
[core]/esx_notify/nui/css/style.css | 436 ++++++++++++++--------------
[core]/esx_notify/nui/index.html | 50 +++-
[core]/esx_notify/nui/js/script.js | 260 +++++++++--------
[core]/esx_notify/readme.md | 22 +-
6 files changed, 410 insertions(+), 364 deletions(-)
diff --git a/[core]/esx_notify/Notify.lua b/[core]/esx_notify/Notify.lua
index 54bc48c7..d690fbd6 100644
--- a/[core]/esx_notify/Notify.lua
+++ b/[core]/esx_notify/Notify.lua
@@ -85,5 +85,5 @@ if Debug then
RegisterCommand("notify4", function()
ESX.ShowNotification("You Did something ~r~WRONG~s~!", "warning", 3000, "~y~Warning~s~")
- end)
-end
+ end)
+end
\ No newline at end of file
diff --git a/[core]/esx_notify/fxmanifest.lua b/[core]/esx_notify/fxmanifest.lua
index 30f0ed5c..647d07a7 100644
--- a/[core]/esx_notify/fxmanifest.lua
+++ b/[core]/esx_notify/fxmanifest.lua
@@ -2,7 +2,7 @@ fx_version 'adamant'
lua54 'yes'
game 'gta5'
-version '1.13.1'
+version '1.13.3'
author 'ESX-Framework'
description 'A beautiful and simple NUI notification system for ESX'
diff --git a/[core]/esx_notify/nui/css/style.css b/[core]/esx_notify/nui/css/style.css
index 30ff7495..6d02c9a1 100644
--- a/[core]/esx_notify/nui/css/style.css
+++ b/[core]/esx_notify/nui/css/style.css
@@ -1,337 +1,337 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap");
:root {
- --background: rgba(20, 20, 20, 0.9);
- --text-color: #ffffff;
- --text-secondary: rgba(255, 255, 255, 0.7);
- --success-color: #2ecc71;
- --success-border: #1f9c4d;
- --error-color: #e74c3c;
- --error-border: #c0392b;
- --info-color: #3498db;
- --info-border: #2980b9;
- --warning-color: #f39c12;
- --warning-border: #d35400;
+ --background: rgba(20, 20, 20, 0.9);
+ --text-color: #ffffff;
+ --text-secondary: rgba(255, 255, 255, 0.7);
+ --success-color: #2ecc71;
+ --success-border: #1f9c4d;
+ --error-color: #e74c3c;
+ --error-border: #c0392b;
+ --info-color: #3498db;
+ --info-border: #2980b9;
+ --warning-color: #f39c12;
+ --warning-border: #d35400;
}
* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
}
body {
- width: 100vw;
- height: 100vh;
- font-family: "Poppins", sans-serif;
- overflow: hidden;
+ width: 100vw;
+ height: 100vh;
+ font-family: "Poppins", sans-serif;
+ overflow: hidden;
}
-#root {
- position: fixed;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 10px;
- max-height: 80vh;
- z-index: 1000;
+.notification-container {
+ position: fixed;
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 10px;
+ max-height: 80vh;
+ z-index: 1000;
}
-#root.middle-right {
- right: 2rem;
- top: 50%;
- transform: translateY(-50%);
+#middle-right {
+ right: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
}
-#root.middle-left {
- left: 2rem;
- top: 50%;
- transform: translateY(-50%);
+#middle-left {
+ left: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
}
-#root.top-right {
- right: 2rem;
- top: 2rem;
+#top-right {
+ right: 2rem;
+ top: 2rem;
}
-#root.top-left {
- left: 2rem;
- top: 2rem;
+#top-left {
+ left: 2rem;
+ top: 2rem;
}
-#root.top-middle {
- left: 50%;
- top: 2rem;
- transform: translateX(-50%);
+#top-middle {
+ left: 50%;
+ top: 2rem;
+ transform: translateX(-50%);
}
-#root.bottom-right {
- right: 2rem;
- bottom: 2rem;
+#bottom-right {
+ right: 2rem;
+ bottom: 2rem;
}
-#root.bottom-left {
- left: 2rem;
- bottom: 2rem;
+#bottom-left {
+ left: 2rem;
+ bottom: 2rem;
}
-#root.bottom-middle {
- left: 50%;
- bottom: 2rem;
- transform: translateX(-50%);
+#bottom-middle {
+ left: 50%;
+ bottom: 2rem;
+ transform: translateX(-50%);
}
.notify {
- display: flex;
- width: 300px;
- background: var(--background);
- border-radius: 8px;
- overflow: hidden;
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
- position: relative;
- padding: 12px;
- align-items: center;
- border-left: 4px solid #555;
+ display: flex;
+ width: 300px;
+ background: var(--background);
+ border-radius: 8px;
+ overflow: hidden;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
+ position: relative;
+ padding: 12px;
+ align-items: center;
+ border-left: 4px solid #555;
}
.notify-success {
- border-left-color: var(--success-border);
+ border-left-color: var(--success-border);
}
.notify-error {
- border-left-color: var(--error-border);
+ border-left-color: var(--error-border);
}
.notify-info {
- border-left-color: var(--info-border);
+ border-left-color: var(--info-border);
}
.notify-warning {
- border-left-color: var(--warning-border);
+ border-left-color: var(--warning-border);
}
.notify-icon-container {
- margin-right: 12px;
- display: flex;
- align-items: center;
- justify-content: center;
+ margin-right: 12px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
}
.hexagon {
- position: relative;
- width: 40px;
- height: 40px;
- display: flex;
- align-items: center;
- justify-content: center;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+ position: relative;
+ width: 40px;
+ height: 40px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ background: linear-gradient(145deg, var(--icon-color), rgba(0, 0, 0, 0.7));
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.hexagon::before {
- content: "";
- position: absolute;
- top: 3px;
- left: 3px;
- right: 3px;
- bottom: 3px;
- background: var(--background);
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 1;
+ content: "";
+ position: absolute;
+ top: 3px;
+ left: 3px;
+ right: 3px;
+ bottom: 3px;
+ background: var(--background);
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 1;
}
.hexagon::after {
- content: "";
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
- opacity: 0.4;
- clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
- z-index: 2;
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(145deg, var(--icon-color) 10%, transparent 70%);
+ opacity: 0.4;
+ clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
+ z-index: 2;
}
.hexagon .material-symbols-outlined {
- color: var(--icon-color);
- font-size: 20px;
- position: relative;
- z-index: 3;
- filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
- display: flex;
- align-items: center;
- justify-content: center;
- height: 24px;
- width: 24px;
- margin-top: -1px;
+ color: var(--icon-color);
+ font-size: 20px;
+ position: relative;
+ z-index: 3;
+ filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.5));
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 24px;
+ width: 24px;
+ margin-top: -1px;
}
.notify-content {
- flex: 1;
- position: relative;
- padding-bottom: 8px;
+ flex: 1;
+ position: relative;
+ padding-bottom: 8px;
}
.notify-title {
- color: var(--text-color);
- font-size: 14px;
- font-weight: 600;
- margin-bottom: 2px;
+ color: var(--text-color);
+ font-size: 14px;
+ font-weight: 600;
+ margin-bottom: 2px;
}
.notify-text {
- color: var(--text-secondary);
- font-size: 12px;
- font-weight: 400;
+ color: var(--text-secondary);
+ font-size: 12px;
+ font-weight: 400;
}
.notify-progress {
- position: absolute;
- bottom: 0;
- left: 0;
- height: 2px;
- width: 100%;
- border-radius: 1px;
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ height: 2px;
+ width: 100%;
+ border-radius: 1px;
}
.material-symbols-outlined {
- font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 48;
+ font-variation-settings: "FILL" 1, "wght" 400, "GRAD" 0, "opsz" 48;
}
.notify-warning .material-symbols-outlined,
.notify-error .material-symbols-outlined {
- margin-top: -2px;
+ margin-top: -2px;
}
-#root.top-right .fadeIn,
-#root.bottom-right .fadeIn,
-#root.middle-right .fadeIn {
- animation: fadeIn-right 0.3s ease-in-out;
+#top-right .fadeIn,
+#bottom-right .fadeIn,
+#middle-right .fadeIn {
+ animation: fadeIn-right 0.3s ease-in-out;
}
-#root.top-left .fadeIn,
-#root.bottom-left .fadeIn,
-#root.middle-left .fadeIn {
- animation: fadeIn-left 0.3s ease-in-out;
+#top-left .fadeIn,
+#bottom-left .fadeIn,
+#middle-left .fadeIn {
+ animation: fadeIn-left 0.3s ease-in-out;
}
-#root.top-middle .fadeIn {
- animation: fadeIn-top 0.3s ease-in-out;
+#top-middle .fadeIn {
+ animation: fadeIn-top 0.3s ease-in-out;
}
-#root.bottom-middle .fadeIn {
- animation: fadeIn-bottom 0.3s ease-in-out;
+#bottom-middle .fadeIn {
+ animation: fadeIn-bottom 0.3s ease-in-out;
}
.fadeOut {
- opacity: 0;
+ opacity: 0;
}
-#root.top-right .fadeOut,
-#root.bottom-right .fadeOut,
-#root.middle-right .fadeOut {
- animation: fadeOut-right 0.5s ease-in-out;
+#top-right .fadeOut,
+#bottom-right .fadeOut,
+#middle-right .fadeOut {
+ animation: fadeOut-right 0.5s ease-in-out;
}
-#root.top-left .fadeOut,
-#root.bottom-left .fadeOut,
-#root.middle-left .fadeOut {
- animation: fadeOut-left 0.5s ease-in-out;
+#top-left .fadeOut,
+#bottom-left .fadeOut,
+#middle-left .fadeOut {
+ animation: fadeOut-left 0.5s ease-in-out;
}
-#root.top-middle .fadeOut {
- animation: fadeOut-top 0.5s ease-in-out;
+#top-middle .fadeOut {
+ animation: fadeOut-top 0.5s ease-in-out;
}
-#root.bottom-middle .fadeOut {
- animation: fadeOut-bottom 0.5s ease-in-out;
+#bottom-middle .fadeOut {
+ animation: fadeOut-bottom 0.5s ease-in-out;
}
@keyframes fadeIn-right {
- from {
- opacity: 0;
- transform: translateX(50px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
+ from {
+ opacity: 0;
+ transform: translateX(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
}
@keyframes fadeIn-left {
- from {
- opacity: 0;
- transform: translateX(-50px);
- }
- to {
- opacity: 1;
- transform: translateX(0);
- }
+ from {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateX(0);
+ }
}
@keyframes fadeIn-top {
- from {
- opacity: 0;
- transform: translateY(-50px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
+ from {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
@keyframes fadeIn-bottom {
- from {
- opacity: 0;
- transform: translateY(50px);
- }
- to {
- opacity: 1;
- transform: translateY(0);
- }
+ from {
+ opacity: 0;
+ transform: translateY(50px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
@keyframes fadeOut-right {
- from {
- opacity: 1;
- transform: translateX(0);
- }
- to {
- opacity: 0;
- transform: translateX(50px);
- }
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(50px);
+ }
}
@keyframes fadeOut-left {
- from {
- opacity: 1;
- transform: translateX(0);
- }
- to {
- opacity: 0;
- transform: translateX(-50px);
- }
+ from {
+ opacity: 1;
+ transform: translateX(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateX(-50px);
+ }
}
@keyframes fadeOut-top {
- from {
- opacity: 1;
- transform: translateY(0);
- }
- to {
- opacity: 0;
- transform: translateY(-50px);
- }
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(-50px);
+ }
}
@keyframes fadeOut-bottom {
- from {
- opacity: 1;
- transform: translateY(0);
- }
- to {
- opacity: 0;
- transform: translateY(50px);
- }
+ from {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ to {
+ opacity: 0;
+ transform: translateY(50px);
+ }
}
diff --git a/[core]/esx_notify/nui/index.html b/[core]/esx_notify/nui/index.html
index 76a62faa..9bdb502c 100644
--- a/[core]/esx_notify/nui/index.html
+++ b/[core]/esx_notify/nui/index.html
@@ -1,15 +1,39 @@
-
-
-
-
-
ESX Notifications
-
-
-
-
-
-
-
-
+
+
+
+
+
+
ESX Notifications
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+