From fe654facee0a04c3a24276ffda5615c35afed07b Mon Sep 17 00:00:00 2001
From: Kakarot <57848836+GhzGarage@users.noreply.github.com>
Date: Thu, 13 Mar 2025 15:50:32 -0500
Subject: [PATCH 1/3] Styling update
---
html/css/drawtext.css | 47 ++++++++---
html/css/style.css | 133 ++++++++++++++++++++++--------
html/index.html | 4 +-
html/js/app.js | 31 +++----
html/js/config.js | 68 ++++++++-------
html/js/drawtext.js | 186 +++++++++++++++++++++---------------------
html/js/testing.js | 44 ----------
html/js/utils.js | 27 ------
8 files changed, 287 insertions(+), 253 deletions(-)
delete mode 100644 html/js/testing.js
delete mode 100644 html/js/utils.js
diff --git a/html/css/drawtext.css b/html/css/drawtext.css
index 36832d5..f6c920b 100644
--- a/html/css/drawtext.css
+++ b/html/css/drawtext.css
@@ -1,9 +1,36 @@
-@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap");
-
:root {
+ /* Typography */
+ --font-primary: "Exo 2", sans-serif;
+ --font-weight-regular: 400;
+ --font-weight-medium: 500;
+ --font-weight-bold: 700;
+ --font-weight-light: 300;
+ /* Colors */
+ --md-primary: #1c75d2;
+ --md-primary-container: #6facec;
+ --md-error: #c10114;
+ --md-error-container: #fe4255;
+ --md-success: #20bb44;
+ --md-success-container: #6ae587;
+ --md-warning: #ff9800;
+ --md-warning-container: #ffc107;
+ --md-info: #2197f2;
+ --md-info-container: #7ac1f7;
+ --md-surface: #fffbff;
+ --md-on-surface: #1c1b1f;
+
+ /* Custom Variables */
--primary-bg: rgba(23, 23, 23, 90%);
- --active-bg: #dc143c;
+ --active-bg: var(--md-error);
--font-color: white;
+
+ /* Elevation */
+ --md-elevation-1: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);
+
+ /* Border Radius */
+ --md-radius-small: 5px;
+ --md-radius-medium: 10px;
+ --md-radius-extra-small: 0.15rem;
}
#drawtext-container {
@@ -13,8 +40,8 @@
overflow: hidden;
padding: 0;
margin: 0;
- font-family: "Poppins", sans-serif !important;
- font-weight: 300;
+ font-family: var(--font-primary) !important;
+ font-weight: var(--font-weight-light);
}
.text {
@@ -23,8 +50,8 @@
color: var(--font-color);
margin-top: 0.5rem;
padding: 0.45rem;
- border-radius: 0.15rem;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
+ border-radius: var(--md-radius-extra-small);
+ box-shadow: var(--md-elevation-1);
}
@media (width: 3840px) and (height: 2160px) {
@@ -35,8 +62,8 @@
overflow: hidden;
padding: 0;
margin: 0;
- font-family: "Poppins", sans-serif !important;
- font-weight: 300;
+ font-family: var(--font-primary) !important;
+ font-weight: var(--font-weight-light);
font-size: 1.5vh;
}
}
@@ -94,4 +121,4 @@
transition: 0.5s;
left: -100px;
opacity: 0;
-}
\ No newline at end of file
+}
diff --git a/html/css/style.css b/html/css/style.css
index 1211654..62ae7d2 100644
--- a/html/css/style.css
+++ b/html/css/style.css
@@ -1,3 +1,56 @@
+:root {
+ /* Typography */
+ --font-primary: "Exo 2", sans-serif;
+ --font-weight-regular: 400;
+ --font-weight-medium: 500;
+ --font-weight-bold: 700;
+ --font-weight-light: 300;
+
+ /* Colors */
+ --md-primary: #0061a4;
+ --md-on-primary: #ffffff;
+ --md-primary-container: #d1e4ff;
+ --md-on-primary-container: #001d36;
+
+ --md-error: #ba1a1a;
+ --md-on-error: #ffffff;
+ --md-error-container: #ffdad6;
+ --md-on-error-container: #410002;
+
+ --md-success: #006e1c;
+ --md-on-success: #ffffff;
+ --md-success-container: #9df996;
+ --md-on-success-container: #002106;
+
+ --md-warning: #7d5800;
+ --md-on-warning: #ffffff;
+ --md-warning-container: #ffdf93;
+ --md-on-warning-container: #271900;
+
+ --md-info: #0062a1;
+ --md-on-info: #ffffff;
+ --md-info-container: #d0e4ff;
+ --md-on-info-container: #001d35;
+
+ /* Surface colors */
+ --md-surface: #fcfcff;
+ --md-on-surface: #1a1c1e;
+ --md-surface-variant: #dfe2eb;
+ --md-on-surface-variant: #43474e;
+
+ /* Elevation */
+ --md-elevation-1: 0px 1px 3px 1px rgba(0, 0, 0, 0.15);
+
+ /* Border Radius */
+ --md-radius-small: 4px;
+ --md-radius-medium: 8px;
+}
+
+* {
+ font-family: var(--font-primary);
+ font-weight: var(--font-weight-regular);
+}
+
html::-webkit-scrollbar {
display: none;
}
@@ -5,77 +58,91 @@ html::-webkit-scrollbar {
@media (width: 3840px) and (height: 2160px) {
.success {
background-color: rgba(23, 23, 23, 90%);
- border-radius: 10px;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
- border-left: 0.5rem solid #20bb44;
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 0.5rem solid var(--md-success);
font-size: 1.5vh;
}
.primary {
background-color: rgba(23, 23, 23, 90%);
- border-radius: 10px;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
- border-left: 5px solid #1c75d2;
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 5px solid var(--md-primary);
font-size: 1.5vh;
}
.error {
background-color: rgba(23, 23, 23, 90%);
- border-radius: 10px;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
- border-left: 5px solid #c10114;
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 5px solid var(--md-error);
+ font-size: 1.5vh;
+ }
+
+ .warning {
+ background-color: rgba(23, 23, 23, 90%);
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 5px solid var(--md-warning);
font-size: 1.5vh;
}
.police {
background-color: rgba(23, 23, 23, 90%);
- border-radius: 10px;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
- border-left: 5px solid #2197f2;
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 5px solid var(--md-info);
font-size: 1.5vh;
}
.ambulance {
background-color: rgba(23, 23, 23, 90%);
- border-radius: 10px;
- box-shadow: 0rem 0rem 0.1rem 0.05rem #000000;
- border-left: 5px solid #f44236;
+ color: var(--md-on-surface);
+ box-shadow: var(--md-elevation-1);
+ border-left: 5px solid var(--md-error);
font-size: 1.5vh;
}
}
.success {
- background-color: #20bb44;
- border-radius: 5px;
- border: 1px solid #6ae587;
+ background-color: var(--md-success-container);
+ color: var(--md-on-success-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
.primary {
- background-color: #1c75d2;
- border-radius: 5px;
- border: 1px solid #6facec;
+ background-color: var(--md-primary-container);
+ color: var(--md-on-primary-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
.warning {
- background-color: #ff9800;
- border-radius: 5px;
- border: 1px solid #ffc107;
+ background-color: var(--md-warning-container);
+ color: var(--md-on-warning-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
.error {
- background-color: #c10114;
- border-radius: 5px;
- border: 1px solid #fe4255;
+ background-color: var(--md-error-container);
+ color: var(--md-on-error-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
.police {
- background-color: #2197f2;
- border-radius: 5px;
- border: 1px solid #7ac1f7;
+ background-color: var(--md-info-container);
+ color: var(--md-on-info-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
.ambulance {
- background-color: #f44236;
- border-radius: 5px;
- border: 1px solid #f88e86;
+ background-color: var(--md-error-container);
+ color: var(--md-on-error-container);
+ padding: 12px 16px;
+ font-weight: var(--font-weight-medium);
}
diff --git a/html/index.html b/html/index.html
index 13c31e3..9d5286f 100644
--- a/html/index.html
+++ b/html/index.html
@@ -1,6 +1,6 @@
-
+
@@ -11,7 +11,7 @@
-
+
diff --git a/html/js/app.js b/html/js/app.js
index 7a9b374..007f725 100644
--- a/html/js/app.js
+++ b/html/js/app.js
@@ -1,16 +1,29 @@
-import { registerWindowMethods } from "./testing.js";
-import { isEnvBrowser } from "./utils.js";
-import { determineStyleFromVariant, DEV_MODE, fetchNotifyConfig, NOTIFY_CONFIG } from "./config.js";
+import { determineStyleFromVariant, fetchNotifyConfig, NOTIFY_CONFIG } from "./config.js";
const { useQuasar } = Quasar;
const { onMounted, onUnmounted } = Vue;
+const fetchNui = async (evName, data) => {
+ const resourceName = window.GetParentResourceName();
+
+ const rawResp = await fetch(`https://${resourceName}/${evName}`, {
+ body: JSON.stringify(data),
+ headers: {
+ "Content-Type": "application/json; charset=UTF8",
+ },
+ method: "POST",
+ });
+
+ return await rawResp.json();
+};
+
+window.fetchNui = fetchNui;
+
const app = Vue.createApp({
setup() {
const $q = useQuasar();
const showNotif = async ({ data }) => {
- // Otherwise we process any old MessageEvent with a data property
if (data?.action !== "notify") return;
const { text, length, type, caption, icon: dataIcon } = data;
@@ -20,21 +33,15 @@ const app = Vue.createApp({
icon = dataIcon;
}
- // Make sure we have sucessfully fetched out config properly
if (!NOTIFY_CONFIG) {
console.error("The notification config did not load properly, trying again for next time");
- // Lets check again to see if it exists
await fetchNotifyConfig();
- // If we have a config lets re-run notification with same data, this
- // isn't recursive though.
if (NOTIFY_CONFIG) return showNotif({ data });
}
$q.notify({
message: text,
multiLine: text.length > 100,
- // If our text is larger than a 100 characters,
- // we should use multiline notifications
group: NOTIFY_CONFIG.NotificationStyling.group ?? false,
progress: NOTIFY_CONFIG.NotificationStyling.progress ?? true,
position: NOTIFY_CONFIG.NotificationStyling.position ?? "right",
@@ -56,7 +63,3 @@ const app = Vue.createApp({
app.use(Quasar, { config: {} });
app.mount("#q-app");
-
-if (DEV_MODE || isEnvBrowser()) {
- registerWindowMethods();
-}
diff --git a/html/js/config.js b/html/js/config.js
index 3757238..5ff6925 100644
--- a/html/js/config.js
+++ b/html/js/config.js
@@ -1,45 +1,53 @@
-import { fetchNui, isEnvBrowser } from "./utils.js";
-import { BrowserMockConfigData } from "./testing.js";
-
-export const DEV_MODE = false;
-
-/**
- * @typedef NotiVariantData
- * @property {string} icon
- * @property {string} color
- **/
-
-/**
- * Will hold config statically outside of Vue state
- * @property {Record
} VariantDefinitions
- * @property {Record} NotificationStyling
- **/
export let NOTIFY_CONFIG = null;
-/**
- * Pure function taking a notification type and returning an object
- * with style details
- * @param {string} variant
- * @returns NotiVariantData
- **/
+const defaultConfig = {
+ NotificationStyling: {
+ group: true,
+ position: "top-right",
+ progress: true,
+ },
+ VariantDefinitions: {
+ success: {
+ classes: "success",
+ icon: "done",
+ },
+ primary: {
+ classes: "primary",
+ icon: "info",
+ },
+ error: {
+ classes: "error",
+ icon: "dangerous",
+ },
+ police: {
+ classes: "police",
+ icon: "local_police",
+ },
+ ambulance: {
+ classes: "ambulance",
+ icon: "fas fa-ambulance",
+ },
+ },
+};
+
export const determineStyleFromVariant = (variant) => {
const variantData = NOTIFY_CONFIG.VariantDefinitions[variant];
if (!variantData) throw new Error(`Style of type: ${variant}, does not exist in the config`);
return variantData;
};
-// Fetch and set NOTIFY_CONFIG from client script callback
export const fetchNotifyConfig = async () => {
- NOTIFY_CONFIG = await fetchNui("getNotifyConfig", {}, BrowserMockConfigData);
- if (isEnvBrowser() || DEV_MODE) {
- console.log("Fetched Config:");
- console.dir(NOTIFY_CONFIG);
+ try {
+ NOTIFY_CONFIG = await window.fetchNui("getNotifyConfig", {});
+ if (!NOTIFY_CONFIG) {
+ NOTIFY_CONFIG = defaultConfig;
+ }
+ } catch (error) {
+ console.error("Failed to fetch notification config, using default", error);
+ NOTIFY_CONFIG = defaultConfig;
}
};
-// We specifically wait for all other files to load
-// just in case of a race condition between client handlers
-// and NUI fetch call
window.addEventListener("load", async () => {
await fetchNotifyConfig();
});
diff --git a/html/js/drawtext.js b/html/js/drawtext.js
index 975d6e1..e93dad0 100644
--- a/html/js/drawtext.js
+++ b/html/js/drawtext.js
@@ -1,124 +1,124 @@
let direction = null;
const drawText = async (textData) => {
- const text = document.getElementById("text");
- let {position} = textData;
- switch (textData.position) {
- case "left":
- addClass(text, position);
- direction = "left";
- break;
- case "top":
- addClass(text, position);
- direction = "top";
- break;
- case "right":
- addClass(text, position);
- direction = "right";
- break;
- default:
- addClass(text, "left");
- direction = "left";
- break;
- }
+ const text = document.getElementById("text");
+ let { position } = textData;
+ switch (textData.position) {
+ case "left":
+ addClass(text, position);
+ direction = "left";
+ break;
+ case "top":
+ addClass(text, position);
+ direction = "top";
+ break;
+ case "right":
+ addClass(text, position);
+ direction = "right";
+ break;
+ default:
+ addClass(text, "left");
+ direction = "left";
+ break;
+ }
- text.innerHTML = textData.text;
- document.getElementById("drawtext-container").style.display = "block";
- await sleep(100);
- addClass(text, "show");
+ text.innerHTML = textData.text;
+ document.getElementById("drawtext-container").style.display = "block";
+ await sleep(100);
+ addClass(text, "show");
};
const changeText = async (textData) => {
- const text = document.getElementById("text");
- let {position} = textData;
+ const text = document.getElementById("text");
+ let { position } = textData;
- removeClass(text, "show");
- addClass(text, "pressed");
- addClass(text, "hide");
+ removeClass(text, "show");
+ addClass(text, "pressed");
+ addClass(text, "hide");
- await sleep(500);
- removeClass(text, "left");
- removeClass(text, "right");
- removeClass(text, "top");
- removeClass(text, "bottom");
- removeClass(text, "hide");
- removeClass(text, "pressed");
-
- switch (textData.position) {
- case "left":
- addClass(text, position);
- direction = "left";
- break;
- case "top":
- addClass(text, position);
- direction = "top";
- break;
- case "right":
- addClass(text, position);
- direction = "right";
- break;
- default:
- addClass(text, "left");
- direction = "left";
- break;
- }
- text.innerHTML = textData.text;
-
- await sleep(100);
- text.classList.add("show");
-};
-
-const hideText = async () => {
- const text = document.getElementById("text");
- removeClass(text, "show");
- addClass(text, "hide");
-
- setTimeout(() => {
+ await sleep(500);
removeClass(text, "left");
removeClass(text, "right");
removeClass(text, "top");
removeClass(text, "bottom");
removeClass(text, "hide");
removeClass(text, "pressed");
- document.getElementById("drawtext-container").style.display = "none";
- }, 1000);
+
+ switch (textData.position) {
+ case "left":
+ addClass(text, position);
+ direction = "left";
+ break;
+ case "top":
+ addClass(text, position);
+ direction = "top";
+ break;
+ case "right":
+ addClass(text, position);
+ direction = "right";
+ break;
+ default:
+ addClass(text, "left");
+ direction = "left";
+ break;
+ }
+ text.innerHTML = textData.text;
+
+ await sleep(100);
+ text.classList.add("show");
+};
+
+const hideText = async () => {
+ const text = document.getElementById("text");
+ removeClass(text, "show");
+ addClass(text, "hide");
+
+ setTimeout(() => {
+ removeClass(text, "left");
+ removeClass(text, "right");
+ removeClass(text, "top");
+ removeClass(text, "bottom");
+ removeClass(text, "hide");
+ removeClass(text, "pressed");
+ document.getElementById("drawtext-container").style.display = "none";
+ }, 1000);
};
const keyPressed = () => {
- const text = document.getElementById("text");
- addClass(text, "pressed");
+ const text = document.getElementById("text");
+ addClass(text, "pressed");
};
window.addEventListener("message", (event) => {
- const data = event.data;
- const action = data.action;
- const textData = data.data;
- switch (action) {
- case "DRAW_TEXT":
- return drawText(textData);
- case "CHANGE_TEXT":
- return changeText(textData);
- case "HIDE_TEXT":
- return hideText();
- case "KEY_PRESSED":
- return keyPressed();
- default:
- return;
- }
+ const data = event.data;
+ const action = data.action;
+ const textData = data.data;
+ switch (action) {
+ case "DRAW_TEXT":
+ return drawText(textData);
+ case "CHANGE_TEXT":
+ return changeText(textData);
+ case "HIDE_TEXT":
+ return hideText();
+ case "KEY_PRESSED":
+ return keyPressed();
+ default:
+ return;
+ }
});
const sleep = (ms) => {
- return new Promise((resolve) => setTimeout(resolve, ms));
+ return new Promise((resolve) => setTimeout(resolve, ms));
};
const removeClass = (element, name) => {
- if (element.classList.contains(name)) {
- element.classList.remove(name);
- }
+ if (element.classList.contains(name)) {
+ element.classList.remove(name);
+ }
};
const addClass = (element, name) => {
- if (!element.classList.contains(name)) {
- element.classList.add(name);
- }
+ if (!element.classList.contains(name)) {
+ element.classList.add(name);
+ }
};
diff --git a/html/js/testing.js b/html/js/testing.js
deleted file mode 100644
index 5181f57..0000000
--- a/html/js/testing.js
+++ /dev/null
@@ -1,44 +0,0 @@
-// Will register dev utilities on window
-export const registerWindowMethods = () => {
- window.SendNotification = (data) => {
- window.dispatchEvent(
- new MessageEvent("message", {
- data: {
- action: "notify",
- ...data,
- },
- })
- );
- };
-};
-
-// Used for browser env handling
-export const BrowserMockConfigData = {
- NotificationStyling: {
- group: true,
- position: "top-right",
- progress: true,
- },
- VariantDefinitions: {
- success: {
- classes: "success",
- icon: "done",
- },
- primary: {
- classes: "primary",
- icon: "info",
- },
- error: {
- classes: "error",
- icon: "dangerous",
- },
- police: {
- classes: "police",
- icon: "local_police",
- },
- ambulance: {
- classes: "ambulance",
- icon: "fas fa-ambulance",
- },
- },
-};
diff --git a/html/js/utils.js b/html/js/utils.js
deleted file mode 100644
index bf2fb8c..0000000
--- a/html/js/utils.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// Returns whether we are in browser or not
-export const isEnvBrowser = () => !window.invokeNative;
-
-/**
- * Real simple wrapper around fetch api for NUI focus
- * it will return the mockData param if we are in browser. So we don't
- * make a useless request to a hostname that doesn't exist.
- * @param evName {string} - The callback event name/type
- * @param data {any} - Optional `body` data JSON stringified & passed with the request
- * @param mockData {any} - Mock data to return if this is running in browser
- * @return Promise
- **/
-export const fetchNui = async (evName, data, mockData = null) => {
- if (isEnvBrowser()) return mockData;
-
- const resourceName = window.GetParentResourceName();
-
- const rawResp = await fetch(`https://${resourceName}/${evName}`, {
- body: JSON.stringify(data),
- headers: {
- "Content-Type": "application/json; charset=UTF8",
- },
- method: "POST",
- });
-
- return await rawResp.json();
-};
From 23ad1ccb6fcc6eab289ca3f7664a424c47247ef4 Mon Sep 17 00:00:00 2001
From: Ata Revals <47323005+atarevals@users.noreply.github.com>
Date: Sun, 16 Mar 2025 10:51:47 +0330
Subject: [PATCH 2/3] Update fa.lua
---
locale/fa.lua | 129 ++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 114 insertions(+), 15 deletions(-)
diff --git a/locale/fa.lua b/locale/fa.lua
index 1367dac..b2ac5af 100644
--- a/locale/fa.lua
+++ b/locale/fa.lua
@@ -1,22 +1,121 @@
local Translations = {
error = {
- not_online = 'Player online nist !',
- wrong_format = 'Vorodi sahih nist !',
- missing_args = 'Vorodi naghes ast (x, y, z)',
- missing_args2 = 'Tamam vorodi hara vared konid !',
- no_access = 'Shoma dastresi nadarid !',
- company_too_poor = 'Sherkat shoma, pul kafi baraye hoghogh dadan nadarad !',
- item_not_exist = 'In item vojod nadarad',
- too_heavy = 'Inventory kheyli sangin ast !'
+ not_online = 'بازیکن آنلاین نیست',
+ wrong_format = 'فرمت نادرست',
+ missing_args = 'همه اطلاعات وارد نشده است (x, y, z)',
+ missing_args2 = 'باید همه فیلدهای لازم پر شوند!',
+ no_access = 'شما به این دستور دسترسی ندارید',
+ company_too_poor = 'کارفرمای شما پول کافی ندارد',
+ item_not_exist = 'آیتم وجود ندارد',
+ too_heavy = 'فضای کافی در کیف شما نیست',
+ location_not_exist = 'مکان وجود ندارد',
+ duplicate_license = 'لایسنس راکستار تکراری یافت شد',
+ no_valid_license = 'لایسنس راکستار معتبر یافت نشد',
+ not_whitelisted = 'شما در این سرور لیست سفید نیستید',
+ server_already_open = 'سرور قبلاً باز است',
+ server_already_closed = 'سرور قبلاً بسته است',
+ no_permission = 'شما اجازه این کار را ندارید...',
+ no_waypoint = 'هیچ نقطهای تنظیم نشده است.',
+ tp_error = 'خطا در هنگام انتقال.',
+ },
+ success = {
+ server_opened = 'سرور باز شد',
+ server_closed = 'سرور بسته شد',
+ teleported_waypoint = 'به نقطه مشخص شده منتقل شدید.',
},
- success = {},
info = {
- received_paycheck = 'Hoghogh shoma variz shod : $%{value}',
- job_info = 'Shoghl: %{value} | Daraje: %{value2} | Dar hal kar: %{value3}',
- gang_info = 'Gang: %{value} | Daraje: %{value2}',
- on_duty = 'Shoma dar hal kar hastid (on-duty)!',
- off_duty = 'Shoma az kar kharej shodid (off-duty)!'
- }
+ received_paycheck = 'شما حقوق خود را به مبلغ $%{value} دریافت کردید',
+ job_info = 'شغل: %{value} | سطح: %{value2} | در حال کار: %{value3}',
+ gang_info = 'گروه: %{value} | سطح: %{value2}',
+ on_duty = 'شما اکنون در حال کار هستید!',
+ off_duty = 'شما اکنون خارج از کار هستید!',
+ checking_ban = 'سلام %s. در حال بررسی وضعیت ممنوعیت شما هستیم.',
+ join_server = 'خوش آمدید %s به {نام سرور}.',
+ checking_whitelisted = 'سلام %s. در حال بررسی وضعیت مجاز بودن شما هستیم.',
+ exploit_banned = 'شما به دلیل تقلب ممنوع شدهاید. برای اطلاعات بیشتر به دیسکورد ما مراجعه کنید: %{discord}',
+ exploit_dropped = 'شما به دلیل تقلب از سرور خارج شدید',
+ },
+ command = {
+ tp = {
+ help = 'انتقال به بازیکن یا مختصات (فقط ادمین)',
+ params = {
+ x = { name = 'id/x', help = 'شناسه بازیکن یا مختصات X' },
+ y = { name = 'y', help = 'مختصات Y' },
+ z = { name = 'z', help = 'مختصات Z' },
+ },
+ },
+ tpm = { help = 'انتقال به نقطه مشخص شده (فقط ادمین)' },
+ togglepvp = { help = 'تغییر وضعیت پی وی پی (فقط ادمین)' },
+ addpermission = {
+ help = 'ادمینی به بازیکن',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ permission = { name = 'permission', help = 'سطح ادمینی' },
+ },
+ },
+ removepermission = {
+ help = 'حذف ادمینی از بازیکن',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ permission = { name = 'permission', help = 'سطح ادمینی' },
+ },
+ },
+ openserver = { help = 'باز کردن سرور برای همه (فقط ادمین)' },
+ closeserver = {
+ help = 'بستن سرور برای کسانی که ادمینی ندارند (فقط ادمین)',
+ params = {
+ reason = { name = 'reason', help = 'دلیل بستن (اختیاری)' },
+ },
+ },
+ car = {
+ help = 'اسپاون کردن خودرو (فقط ادمین)',
+ params = {
+ model = { name = 'model', help = 'نام مدل خودرو' },
+ },
+ },
+ dv = { help = 'حذف خودرو (فقط ادمین)' },
+ givemoney = {
+ help = 'دادن پول به بازیکن (فقط ادمین)',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ moneytype = { name = 'moneytype', help = 'نوع پول (نقدی، بانکی، کریپتو)' },
+ amount = { name = 'amount', help = 'مقدار پول' },
+ },
+ },
+ setmoney = {
+ help = 'تنظیم مقدار پول بازیکن (فقط ادمین)',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ moneytype = { name = 'moneytype', help = 'نوع پول (نقدی، بانکی، کریپتو)' },
+ amount = { name = 'amount', help = 'مقدار پول' },
+ },
+ },
+ job = { help = 'بررسی شغل' },
+ setjob = {
+ help = 'تنظیم شغل بازیکن (فقط ادمین)',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ job = { name = 'job', help = 'نام شغل' },
+ grade = { name = 'grade', help = 'سطح شغل' },
+ },
+ },
+ gang = { help = 'بررسی گنگ' },
+ setgang = {
+ help = 'تنظیم گنگ بازیکن (فقط ادمین)',
+ params = {
+ id = { name = 'id', help = 'شناسه بازیکن' },
+ gang = { name = 'gang', help = 'نام گنگ' },
+ grade = { name = 'grade', help = 'سطح گنگ' },
+ },
+ },
+ ooc = { help = 'پیام خارج از آر پی' },
+ me = {
+ help = 'ارسال پیام محلی',
+ params = {
+ message = { name = 'message', help = 'پیام' }
+ },
+ },
+ },
}
if GetConvar('qb_locale', 'en') == 'fa' then
From 7f14e90687c15509a975af874e2c334be84b14bc Mon Sep 17 00:00:00 2001
From: Illusion <163570364+illusi0n003@users.noreply.github.com>
Date: Tue, 1 Apr 2025 01:58:30 +0200
Subject: [PATCH 3/3] Add files via upload
Added workbench & attachment to items.
---
shared/items.lua | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/shared/items.lua b/shared/items.lua
index 84de923..6164389 100644
--- a/shared/items.lua
+++ b/shared/items.lua
@@ -382,4 +382,9 @@ QBShared.Items = {
newscam = { name = 'newscam', label = 'News Camera', weight = 100, type = 'item', image = 'newscam.png', unique = true, useable = true, shouldClose = true, description = 'A camera for the news' },
newsmic = { name = 'newsmic', label = 'News Microphone', weight = 100, type = 'item', image = 'newsmic.png', unique = true, useable = true, shouldClose = true, description = 'A microphone for the news' },
newsbmic = { name = 'newsbmic', label = 'Boom Microphone', weight = 100, type = 'item', image = 'newsbmic.png', unique = true, useable = true, shouldClose = true, description = 'A Useable BoomMic' },
-}
+
+ -- Crafting table's
+ item_bench = {name = "item_bench", label = "Workbench", weight = 15000, type = "item", image = "workbench.png", unique = true, useable = true, shouldClose = false, combinable = nil, description = "A workbench to craft items."},
+ attachment_bench = {name = "attachment_bench", label = "Attachment Workbench", weight = 15000, type = "item", image = "attworkbench.png", unique = true, useable = true, shouldClose = false, combinable = nil, description = "A workbench for crafting attachments."},
+
+}
\ No newline at end of file