Compare commits

..

8 Commits

Author SHA1 Message Date
Jim Shield
e984a437df attempt to fix shops for QS-Inv 2025-04-30 16:54:33 +01:00
Jim Shield
0818dae0df change qs-inv metadata call to info 2025-04-30 13:21:39 +01:00
Jim Shield
771a2a3217 fix quasar crafting stash item removal 2025-04-29 23:26:10 +01:00
Jim Shield
04b3f87b32 change CodeM metadata check to info 2025-04-29 19:55:30 +01:00
Jim Shield
6c3d0ffc5e change CodeM client inv check to getUserInventory() 2025-04-29 19:55:09 +01:00
Jim Shield
3f093ce934 fix QS-Inv registerStash function 2025-04-29 17:43:37 +01:00
Jim Shield
9a47ec59b0 bump fxmanifest version 2025-04-29 17:24:20 +01:00
Jim Shield
69ce8d9225 remove nui from jim_bridge, i think its killing things 2025-04-29 17:23:28 +01:00
11 changed files with 15 additions and 977 deletions

View File

@@ -1,6 +1,6 @@
name "Jim_Bridge" name "Jim_Bridge"
author "Jimathy" author "Jimathy"
version "2.0.01" version "2.0.03"
description "Framework Bridge By Jimathy" description "Framework Bridge By Jimathy"
fx_version "cerulean" fx_version "cerulean"
rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.' rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
@@ -16,9 +16,4 @@ files {
} }
-- Version checker -- Version checker
server_scripts { '_versioncheck.lua' } server_scripts { '_versioncheck.lua' }
-- NUI Menu Loading
client_scripts { 'nui/*.lua' }
ui_page 'nui/index.html'
files { 'nui/index.html', 'nui/script.js', 'nui/style.css' }

View File

@@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>QB Menu</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<!-- Font Awesome Icons Import -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css">
<link rel="stylesheet" href="./style.css" />
<script src="./script.js" defer></script>
</head>
<body>
<div id="container">
<div id="buttons"></div>
</div>
<!--
<div id="input-popup" class="hidden">
<div class="input-box">
<div class="input-header">Enter Info</div>
<form id="input-form">
</form>
<div class="input-actions">
<button type="submit" form="input-form" class="input-submit">Submit</button>
<button type="button" class="input-cancel">Cancel</button>
</div>
</div>
</div>
-->
</body>
</html>

View File

@@ -1,138 +0,0 @@
Config = Config or { System = {} }
CreateThread(function()
local fileLoader = assert(load(LoadResourceFile('jim_bridge', ('starter.lua')), ('@@jim_bridge/starter.lua')))
fileLoader()
end)
local headerShown = false
local sendData = nil
local sendModifiers = nil
--Colours for progressbar
local colours = {
["dark.0"] = "#C1C2C5", ["dark.1"] = "#A6A7AB", ["dark.2"] = "#909296", ["dark.3"] = "#5C5F66", ["dark.4"] = "#373A40", ["dark.5"] = "#2C2E33", ["dark.6"] = "#25262B", ["dark.7"] = "#1A1B1E", ["dark.8"] = "#141517", ["dark.9"] = "#101113",
["gray.0"] = "#F8F9FA", ["gray.1"] = "#F1F3F5", ["gray.2"] = "#E9ECEF", ["gray.3"] = "#DEE2E6", ["gray.4"] = "#CED4DA", ["gray.5"] = "#ADB5BD", ["gray.6"] = "#868E96", ["gray.7"] = "#495057", ["gray.8"] = "#343A40", ["gray.9"] = "#212529",
["red.0"] = "#FFF5F5", ["red.1"] = "#FFE3E3", ["red.2"] = "#FFC9C9", ["red.3"] = "#FFA8A8", ["red.4"] = "#FF8787", ["red.5"] = "#FF6B6B", ["red.6"] = "#FA5252", ["red.7"] = "#F03E3E", ["red.8"] = "#E03131", ["red.9"] = "#C92A2A",
["pink.0"] = "#FFF0F6", ["pink.1"] = "#FFDEEB", ["pink.2"] = "#FCC2D7", ["pink.3"] = "#FAA2C1", ["pink.4"] = "#F783AC", ["pink.5"] = "#F06595", ["pink.6"] = "#E64980", ["pink.7"] = "#D6336C", ["pink.8"] = "#C2255C", ["pink.9"] = "#A61E4D",
["grape.0"] = "#F8F0FC", ["grape.1"] = "#F3D9FA", ["grape.2"] = "#EEBEFA", ["grape.3"] = "#E599F7", ["grape.4"] = "#DA77F2", ["grape.5"] = "#CC5DE8", ["grape.6"] = "#BE4BDB", ["grape.7"] = "#AE3EC9", ["grape.8"] = "#9C36B5", ["grape.9"] = "#862E9C",
["violet.0"] = "#F3F0FF", ["violet.1"] = "#E5DBFF", ["violet.2"] = "#D0BFFF", ["violet.3"] = "#B197FC", ["violet.4"] = "#9775FA", ["violet.5"] = "#845EF7", ["violet.6"] = "#7950F2", ["violet.7"] = "#7048E8", ["violet.8"] = "#6741D9", ["violet.9"] = "#5F3DC4",
["indigo.0"] = "#EDF2FF", ["indigo.1"] = "#DBE4FF", ["indigo.2"] = "#BAC8FF", ["indigo.3"] = "#91A7FF", ["indigo.4"] = "#748FFC", ["indigo.5"] = "#5C7CFA", ["indigo.6"] = "#4C6EF5", ["indigo.7"] = "#4263EB", ["indigo.8"] = "#3B5BDB", ["indigo.9"] = "#364FC7",
["blue.0"] = "#E7F5FF", ["blue.1"] = "#D0EBFF", ["blue.2"] = "#A5D8FF", ["blue.3"] = "#74C0FC", ["blue.4"] = "#4DABF7", ["blue.5"] = "#339AF0", ["blue.6"] = "#228BE6", ["blue.7"] = "#1C7ED6", ["blue.8"] = "#1971C2", ["blue.9"] = "#1864AB",
["cyan.0"] = "#E3FAFC", ["cyan.1"] = "#C5F6FA", ["cyan.2"] = "#99E9F2", ["cyan.3"] = "#66D9E8", ["cyan.4"] = "#3BC9DB", ["cyan.5"] = "#22B8CF", ["cyan.6"] = "#15AABF", ["cyan.7"] = "#1098AD", ["cyan.8"] = "#0C8599", ["cyan.9"] = "#0B7285",
["teal.0"] = "#E6FCF5", ["teal.1"] = "#C3FAE8", ["teal.2"] = "#96F2D7", ["teal.3"] = "#63E6BE", ["teal.4"] = "#38D9A9", ["teal.5"] = "#20C997", ["teal.6"] = "#12B886", ["teal.7"] = "#0CA678", ["teal.8"] = "#099268", ["teal.9"] = "#087F5B",
["green.0"] = "#EBFBEE", ["green.1"] = "#D3F9D8", ["green.2"] = "#B2F2BB", ["green.3"] = "#8CE99A", ["green.4"] = "#69DB7C", ["green.5"] = "#51CF66", ["green.6"] = "#40C057", ["green.7"] = "#37B24D", ["green.8"] = "#2F9E44", ["green.9"] = "#2B8A3E",
["lime.0"] = "#F4FCE3", ["lime.1"] = "#E9FAC8", ["lime.2"] = "#D8F5A2", ["lime.3"] = "#C0EB75", ["lime.4"] = "#A9E34B", ["lime.5"] = "#94D82D", ["lime.6"] = "#82C91E", ["lime.7"] = "#74B816", ["lime.8"] = "#66A80F", ["lime.9"] = "#5C940D",
["yellow.0"] = "#FFF9DB", ["yellow.1"] = "#FFF3BF", ["yellow.2"] = "#FFEC99", ["yellow.3"] = "#FFE066", ["yellow.4"] = "#FFD43B", ["yellow.5"] = "#FCC419", ["yellow.6"] = "#FAB005", ["yellow.7"] = "#F59F00", ["yellow.8"] = "#F08C00", ["yellow.9"] = "#E67700",
["orange.0"] = "#FFF4E6", ["orange.1"] = "#FFE8CC", ["orange.2"] = "#FFD8A8", ["orange.3"] = "#FFC078", ["orange.4"] = "#FFA94D", ["orange.5"] = "#FF922B", ["orange.6"] = "#FD7E14", ["orange.7"] = "#F76707",["orange.8"] = "#E8590C",["orange.9"] = "#D9480F"
}
-- Functions
function openNuiMenu(data, modifiers)
if not data or not next(data) then return end
for _, v in pairs(data) do
v["icon"] = v["arrow"] and "fas fa-angle-right" or v["icon"] or nil
v["colorScheme"] = v["colourScheme"] and colours[v["colourScheme"]] or (v["colorScheme"] and colours[v["colorScheme"]] or colours["green.7"])
if v["onSelect"] then
v.params = { isAction = true, event = v["onSelect"] }
end
end
SetNuiFocus(true, true)
headerShown = false
sendData = data
sendModifiers = modifiers or {}
SendNUIMessage({ action = 'OPEN_MENU', data = table.clone(data) })
end
local function closeMenu()
sendData = nil
sendModifiers = nil
headerShown = false
SetNuiFocus(false, false)
SendNUIMessage({ action = 'CLOSE_MENU' })
end
local function showHeader(data)
if not data or not next(data) then return end
headerShown = true
sendData = data
SendNUIMessage({ action = 'SHOW_HEADER', data = table.clone(data) })
end
-- Events
RegisterNetEvent("jim_bridge:client:openMenu", function(data) openNuiMenu(data) end)
RegisterNetEvent("jim_bridge:client:closeMenu", function() closeMenu() end)
-- NUI Callbacks
RegisterNUICallback('clickedButton', function(option)
if headerShown then headerShown = false end
PlaySound(-1, "CLICK_BACK", "WEB_NAVIGATION_SOUNDS_PHONE", 0, 0, 1)
SetNuiFocus(false, false)
if sendData then
local data = sendData[tonumber(option)]
sendData = nil
if data then
if data.params and data.params.event then
if data.params.isServer then
TriggerServerEvent(data.params.event, data.params.args)
elseif data.params.isCommand then
ExecuteCommand(data.params.event)
elseif data.params.isQBCommand then
TriggerServerEvent('QBCore:CallCommand', data.params.event, data.params.args)
elseif data.params.isAction then
data.params.event(data.params.args)
else
TriggerEvent(data.params.event, data.params.args)
end
end
end
end
end)
RegisterNUICallback('closeMenu', function()
if sendModifiers and sendModifiers.onExit then sendModifiers.onExit() end -- when close menu is triggered (with esc or using a button to close it) trigger onExit function
headerShown = false
sendModifiers = nil
sendData = nil
SetNuiFocus(false, false)
end)
-- Command and Keymapping
RegisterCommand('playerfocus', function() if headerShown then SetNuiFocus(true, true) end end)
RegisterKeyMapping('playerFocus', 'Give Menu Focus', 'keyboard', 'LMENU')
-- Exports
exports('openMenu', function(data) openNuiMenu(data) end)
exports('closeMenu', function() closeMenu() end)
exports('showHeader', function(data) showHeader(data) end)
-- Input Dialog
-- function inputDialog(title, config)
-- local p = promise.new()
-- local cbId = math.random(111111, 999999)
--
-- RegisterNUICallback("inputResult", function(data, cb)
-- if data.cbId == cbId then
-- cb({})
-- SetNuiFocus(false, false)
-- p:resolve(data.result)
-- end
-- end)
--
-- SendNUIMessage({
-- action = "SHOW_INPUT",
-- title = title,
-- data = config,
-- cbId = cbId
-- })
--
-- SetNuiFocus(true, true)
-- return Citizen.Await(p)
-- end
--
-- exports('inputDialog', inputDialog)

View File

@@ -1,342 +0,0 @@
let buttonParams = [];
let menuItems = [];
const openMenu = (data = null) => {
let html = "<div id='buttons'>";
// Add search as a title-like fixed header
html += `
<div class="title search-container">
<input type="text" id="search-input" placeholder="Search..." autocomplete="off">
</div>
`;
data.forEach((item, index) => {
if (!item.hidden) {
let header = item.header || item.title;
let message = item.txt || item.text || item.description;
let isMenuHeader = item.isMenuHeader;
let isDisabled = item.disabled;
let icon = item.icon;
let progress = item.progress || item.progressbar;
let colour = item.colorScheme;
html += getButtonRender(header, message, index, isMenuHeader, isDisabled, icon, progress, colour);
if (item.params) buttonParams[index] = item.params;
}
});
html += "</div>";
$("#container").html(html);
$('.button').click(function() {
const target = $(this)
if (!target.hasClass('title') && !target.hasClass('disabled')) {
postData(target.attr('id'));
}
});
$("#search-input").on("input", function() {
const value = $(this).val().toLowerCase();
$("#buttons .button, #buttons .title").filter(function(index) {
if (index === 0) return; // Skip the search bar itself (first title)
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
});
});
};
const getButtonRender = (header, message = null, id, isMenuHeader, isDisabled, icon, progress, colour) => {
return `
<div class="${isMenuHeader ? "title" : "button"} ${isDisabled ? "disabled" : ""} " id="${id}">
${icon ? `
<div class="icon">
<img src=${icon} onerror="this.onerror=null; this.remove();">
<i class="${icon}" onerror="this.onerror=null; this.remove();"></i>
</div>
` : " " }
<div class="column">
<div class="header">${header ? `${header}` : " "}</div>
${message ? `<div class="text"> ${message}</div>` : ""}
</div>
</div>
${progress ? `
<div class="progress-container">
<div class="progress-bar" style="width: ${progress}%; background-color: ${colour};"></div>
</div>`
: ""}
`;
};
const closeMenu = () => {
$("#buttons").html(" ");
buttonParams = [];
$("#search-input").hide(); // hide search bar
};
const postData = (id) => {
$.post(`https://${GetParentResourceName()}/clickedButton`, JSON.stringify(parseInt(id) + 1));
return closeMenu();
};
const cancelMenu = () => {
$.post(`https://${GetParentResourceName()}/closeMenu`);
return closeMenu();
};
const filterButtons = (query) => {
const filteredItems = menuItems.filter(item => item.header.toLowerCase().includes(query.toLowerCase()));
openMenu(filteredItems);
};
$("#search-input").on('input', function() {
filterButtons($(this).val());
});
document.onkeyup = function (event) {
const charCode = event.key;
if (charCode == "Escape") {
cancelMenu();
}
};
let inputCallbackId = null;
window.addEventListener("message", (event) => {
const data = event.data;
const buttons = data.data;
const action = data.action;
debugLog("Opening Input Popup", data.data); // Log the input config specifically
switch (action) {
case "OPEN_MENU":
case "SHOW_HEADER":
return openMenu(buttons);
case "CLOSE_MENU":
return closeMenu();
case "SHOW_INPUT":
inputCallbackId = data.cbId;
debugLog("Opening Input Popup", data.data); // Log the input config specifically
return openInputPopup(data.data);
default:
return;
}
});
document.onkeyup = function (event) {
const charCode = event.key;
if (charCode == "Escape") {
cancelMenu();
}
};
const openInputPopup = (config) => {
if (!config || !Array.isArray(config)) {
console.error("Invalid input config: missing or malformed 'fields'", config);
return;
}
const container = document.getElementById("input-popup");
const form = document.getElementById("input-form");
form.innerHTML = ""; // clear form
config.forEach(field => {
let input;
switch (field.type) {
case "text":
case "number":
input = document.createElement("input");
input.type = field.type;
break;
case "radio":
input = document.createElement("input");
input.type = "radio";
break;
case "select":
input = document.createElement("select");
field.options.forEach(opt => {
const option = document.createElement("option");
option.value = opt;
option.textContent = opt;
input.appendChild(option);
});
break;
case "slider":
input = document.createElement("input");
input.type = "range";
input.min = field.min;
input.max = field.max;
input.step = field.step || 1;
break;
case "color":
input = document.createElement("input");
input.type = "color";
break;
}
if (!input) return;
input.name = field.name;
input.className = "input-field";
input.placeholder = field.label || field.placeholder || "";
if (field.required) input.required = true;
const wrapper = document.createElement("div");
wrapper.className = "input-wrapper";
if (field.type === "radio") {
if (field.label) {
const titleLabel = document.createElement("label");
titleLabel.className = "input-label";
titleLabel.textContent = field.label;
wrapper.appendChild(titleLabel);
}
if (Array.isArray(field.options)) {
field.options.forEach(opt => {
const radioWrapper = document.createElement("label");
radioWrapper.className = "radio-wrapper";
const radio = document.createElement("input");
radio.type = "radio";
radio.name = field.name;
radio.value = opt.value;
radio.className = "radio-input";
// Set default checked radio
if (field.default === opt.value) {
radio.checked = true;
}
const label = document.createElement("span");
label.className = "radio-label";
label.textContent = opt.label || opt.value;
radioWrapper.appendChild(radio);
radioWrapper.appendChild(label);
wrapper.appendChild(radioWrapper);
});
}
form.appendChild(wrapper);
return;
}
if (field.type === "color") {
if (field.label) {
const titleLabel = document.createElement("label");
titleLabel.className = "input-label";
titleLabel.textContent = field.label;
wrapper.appendChild(titleLabel);
}
const colorPreview = document.createElement("span");
colorPreview.className = "color-preview";
colorPreview.textContent = input.value;
input.addEventListener("input", () => {
const hex = input.value;
const rgb = hexToRgb(hex);
colorPreview.textContent = `${hex.toUpperCase()} (${rgb})`;
});
wrapper.classList.add("color-picker");
wrapper.appendChild(input);
wrapper.appendChild(colorPreview);
form.appendChild(wrapper);
return;
}
if (field.type === "slider") {
if (field.label) {
const titleLabel = document.createElement("label");
titleLabel.className = "input-label";
titleLabel.textContent = field.label;
wrapper.appendChild(titleLabel);
}
input.value = field.default || field.min;
const sliderValue = document.createElement("div");
sliderValue.className = "slider-values";
sliderValue.innerHTML = `
<span class="slider-min">${field.min}</span>
<span class="slider-current">${input.value}</span>
<span class="slider-max">${field.max}</span>
`;
input.addEventListener("input", () => {
sliderValue.querySelector(".slider-current").textContent = input.value;
});
wrapper.appendChild(sliderValue);
wrapper.appendChild(input);
form.appendChild(wrapper);
return;
}
// Common label
const label = document.createElement("label");
label.className = "input-label";
label.textContent = field.label || field.name || "Input";
wrapper.appendChild(label);
// Input
input.name = field.name;
input.className = "input-field";
if (field.required) input.required = true;
wrapper.appendChild(input);
form.appendChild(wrapper);
form.appendChild(wrapper);
});
form.onsubmit = function (e) {
e.preventDefault();
const data = {};
new FormData(form).forEach((val, key) => {
// checkboxes return "on" when checked
if (form[key].type === "checkbox") {
data[key] = form[key].checked;
} else if (form[key].type === "color") {
const hex = val;
const rgb = hexToRgb(hex);
data[key] = {
hex: hex.toUpperCase(),
rgb: rgb
};
} else {
data[key] = val;
}
});
returnInputData(data);
};
document.querySelector(".input-cancel").onclick = () => {
returnInputData(null);
};
container.classList.remove("hidden");
};
const closeInputPopup = () => {
document.getElementById("input-popup").classList.add("hidden");
};
const returnInputData = (result) => {
$.post(`https://${GetParentResourceName()}/inputResult`, JSON.stringify({
cbId: inputCallbackId,
result
}));
closeInputPopup();
};
const debugLog = (label, data) => {
//console.log(`^4[DEBUG] ${label}`);
//console.log(JSON.stringify(data, null, 2));
};
function hexToRgb(hex) {
const bigint = parseInt(hex.slice(1), 16);
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return `RGB(${r}, ${g}, ${b})`;
}

View File

@@ -1,450 +0,0 @@
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;500&display=swap");
:root {
--font-family: "Poppins", sans-serif !important;
--width: 65%;
--text-colour: white;
--text-colour-hover: black;
--background-button: rgba(23, 23, 23, 85%);
--background-button-hover: rgba(200, 200, 200, 85%);
--background-title: rgba(23, 23, 23, 100%);
/*
--text-colour: black;
--text-colour-hover: white;
--background-button: rgba(200, 200, 200, 85%);
--background-button-hover: rgba(0, 0, 0, 85%);
--background-title: rgba(200, 200, 200);
*/
}
* {
padding: 0;
margin: 0;
font-family: var(--font-family);
font-weight: 300;
}
#container {
position: absolute;
height: auto;
top: 15%;
right: 20%;
z-index: 2;
}
.button {
cursor: pointer;
display: flex;
flex-direction: row !important;
gap: 10px;
}
.title {
cursor: default;
gap: 10px;
display: flex;
flex-direction: row !important;
}
#buttons {
max-height: 80vh;
width: 250%;
overflow-x: none;
overflow-y: auto;
padding: 10px;
}
html, body { background: transparent !important; }
#buttons::-webkit-scrollbar { display: none; }
body::-webkit-scrollbar { display: none; }
.button {
max-width: 56%;
height: 60%;
background-color: var(--background-button);
color: var(--text-colour);
margin: auto;
position: relative;
top: 10%;
overflow: hidden;
padding: 0.45rem;
display: flex;
flex-direction: column;
cursor: pointer;
z-index: 1;
transition-property: color;
transition-duration: 0.1s, 0.2s;
transition-timing-function: linear, ease-in;
}
.button::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background-color: var(--background-button-hover);
z-index: 0;
transition: width 0.2s ease;
}
.button:hover::before {
width: 100%;
}
.button > * {
position: relative;
z-index: 1;
}
.button:hover {
color: var(--text-colour-hover);
}
.icon > img {
width: 2.2vh !important;
}
.icon {
font-size: 1.2vh;
transition-property: all, filter;
transition-duration: 0.1s, 0.3s;
transition-timing-function: linear, ease-in;
display: inline-flex;
align-items: center;
position: static;
justify-content: left;
opacity: 0.5;
}
.button:hover > .icon {
opacity: 1.0;
animation: bounce 2s linear;
filter: drop-shadow(-1px -1px 15px white);
}
.bounce {
animation-name: bounce-4;
animation-timing-function: ease;
}
@keyframes bounce {
0% { transform: scale(1,1); }
10% { transform: scale(1.1); }
30% { transform: scale(1.5); }
50% { transform: scale(1.5); }
100% { transform: scale(1.5); }
}
.title {
font-family: var(--font-family);
width: auto;
max-width: 56%;
height: 60%;
background: var(--background-title);
color: var(--text-colour);
margin: auto;
margin-left: -0.5;
position: relative;
top: 10%;
overflow: hidden;
padding: 0.45rem;
flex-direction: column;
border-left: 0px;
}
.title > div.header {
font-family: var(--font-family);
text-decoration: underline !important;
}
.disabled {
cursor: default;
}
div > .text {
font-family: var(--font-family);
flex-direction: column;
font-size: 1.0vh;
overflow: hidden;
}
div > .header {
font-family: var(--font-family);
width: 100%;
max-width: 100%;
display: flex;
align-items: center;
position: relative;
justify-content: left;
overflow: wrap;
font-size: 1.3vh;
font-weight: 400;
overflow: hidden;
}
/* Search input */
.title.search-container {
background: var(--background-button);
color: var(--text-colour);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
z-index: 3;
}
.title.search-container input[type="text"] {
color: var(--text-colour);
font-family: var(--font-family);
font-size: 1rem;
width: auto;
max-width: 56%;
border: none;
background-color: transparent;
transition: background-color 0.2s ease, color 0.2s ease;
outline: none;
}
.title.search-container input[type="text"]::placeholder {
color: var(--text-colour);
opacity: 0.5;
}
.progress-container {
z-index: 99999;
width: auto;
max-width: 56%;
background-color: var(--background-title);
height: 0.4vh;
padding-left: 0.45rem;
padding-right: 0.45rem;
margin: auto;
}
.progress-bar {
height: 90%;
max-width: auto;
transition: width 0.3s ease-in-out;
}
.hidden {
display: none !important;
}
#input-popup {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
}
.input-box {
font-weight: 300;
background: var(--background-button);
color: var(--text-colour);
width: 25vw;
box-shadow: 0 0 15px var(--background-button-hover);
}
.input-header {
font-size: 1.4rem;
margin-bottom: 1rem;
margin-top: 0.5rem;
font-weight: 500;
text-align: center;
}
.input-actions {
display: flex;
justify-content: space-between;
margin-top: 1rem;
}
.input-actions button {
padding: 0.5rem 1rem;
border: none;
border-radius: 6px;
margin-bottom: 0.8rem;
margin-left: 0.6rem;
margin-right: 0.6rem;
cursor: pointer;
background: var(--background-button);
color: var(--text-colour);
transition: background 0.2s ease;
}
.input-actions button:hover {
color: var(--text-colour-hover);
background: var(--background-button-hover);
}
.input-wrapper {
position: relative;
width: 95%;
padding: 0.1rem;
margin-left: 0.6rem;
margin-bottom: 0.8rem;
background-color: var(--background-title);
overflow: hidden;
}
.input-wrapper::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 0%;
height: 100%;
background-color: var(--background-button-hover);
z-index: 0;
transition: width 0.2s ease;
}
.input-wrapper:focus-within::before {
width: 100%;
}
.input-wrapper:focus-within .input-field {
color: var(--text-colour-hover) !important;
}
.input-wrapper:focus-within .input-label {
color: var(--text-colour-hover) !important;
}
.checkbox-wrapper:has(.checkbox-input:focus) .checkbox-label {
color: var(--text-colour-hover) !important;
}
.input-wrapper:focus-within .color-preview {
color: var(--text-colour-hover) !important;
}
.input-wrapper:has(input[type="range"]:focus) .slider-values {
color: var(--text-colour-hover) !important;
}
.input-wrapper:focus-within .slider-current {
color: var(--text-colour-hover) !important;
}
.input-field {
width: 100%;
position: relative;
z-index: 1;
border: transparent;
background: transparent;
color: var(--text-colour);
font-size: 1rem;
transition: color 0.2s ease;
}
.input-wrapper:hover .input-field {
color: var(--text-colour-hover);
}
.input-label {
display: block;
font-size: 0.9rem;
font-weight: 500;
color: var(--text-colour);
margin-bottom: 0.25rem;
z-index: 1;
position: relative;
}
.radio-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
background: var(--background-title);
border-radius: 4px;
z-index: 1;
}
.radio-input {
transform: scale(1.2);
accent-color: var(--background-button-hover);
z-index: 1;
}
.radio-label {
color: var(--text-colour);
font-size: 0.95rem;
z-index: 1;
}
/* Focus styling */
.radio-wrapper:has(.radio-input:focus) .radio-label {
color: var(--text-colour-hover) !important;
}
.input-wrapper:focus-within .radio-label {
color: var(--text-colour-hover) !important;
}
.input-wrapper.color-picker {
display: flex;
flex-direction: column; /* this is key */
align-items: flex-start;
justify-content: flex-start;
z-index: 1;
}
.input-field[type="color"] {
width: 100%; /* half width */
padding: 0.2rem;
cursor: pointer;
z-index: 1;
}
.color-preview {
display: inline-block;
margin-left: 0.5rem;
font-size: 0.9rem;
color: var(--text-colour);
z-index: 1;
position: relative;
}
.slider-values {
z-index: 2;
position: relative; /* <-- this is the key */
margin-left: 0.6rem;
margin-right: 0.6rem;
display: flex;
justify-content: space-between;
font-size: 0.85rem;
color: var(--text-colour);
margin-bottom: 0.3rem;
}
.slider-current {
font-weight: bold;
color: var(--text-colour);
z-index: 1;
}
.input-field select,
.input-field option {
background-color: var(--background-button);
color: var(--text-colour);
}
.input-field option:hover,
.input-field option:focus {
background-color: var(--background-button-hover);
color: var(--text-colour-hover);
}

View File

@@ -122,7 +122,7 @@ function getPlayerInv(src)
if src then if src then
grabInv = exports[CodeMInv]:GetInventory(src) grabInv = exports[CodeMInv]:GetInventory(src)
else else
grabInv = exports[CodeMInv]:GetClientPlayerInventory() grabInv = exports[CodeMInv]:getUserInventory()
end end
elseif isStarted(QBInv) then elseif isStarted(QBInv) then

View File

@@ -349,7 +349,7 @@ end)
--- ``` --- ```
function dupeWarn(src, item, amount) function dupeWarn(src, item, amount)
local name = getPlayer(src).name local name = getPlayer(src).name
print("^5DupeWarn^7: "..name.." (^1"..tostring(src).."^7) ^2Tried to remove item '^3"..item.."^7' but it wasn't there") print("^5DupeWarn^7: "..name.." (^1"..tostring(src).."^7) ^2Tried to remove item '^3"..item.."^7'^2 but it wasn't there^7")
if not debugMode then if not debugMode then
DropPlayer(src, name.."("..tostring(src)..") Kicked for suspected duplicating items: "..item) DropPlayer(src, name.."("..tostring(src)..") Kicked for suspected duplicating items: "..item)
end end
@@ -432,7 +432,7 @@ function getDurability(item)
for _, v in pairs(itemcheck) do for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot lowestSlot = v.slot
durability = v.metadata.durability durability = v.info.durability
end end
end end
end end
@@ -452,7 +452,7 @@ function getDurability(item)
for _, v in pairs(itemcheck) do for _, v in pairs(itemcheck) do
if v.name == item and v.slot <= lowestSlot then if v.name == item and v.slot <= lowestSlot then
lowestSlot = v.slot lowestSlot = v.slot
durability = v.metadata.durability durability = v.info.durability
end end
end end
end end

View File

@@ -148,6 +148,7 @@ end)
--- }) --- })
--- ``` --- ```
function openShop(data) function openShop(data)
jsonPrint(data)
if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end if (data.job or data.gang) and not jobCheck(data.job or data.gang) then return end
if Config.General.JimShops then if Config.General.JimShops then
@@ -156,12 +157,16 @@ function openShop(data)
elseif isStarted(OXInv) then elseif isStarted(OXInv) then
exports[OXInv]:openInventory('shop', { type = data.shop }) exports[OXInv]:openInventory('shop', { type = data.shop })
elseif isStarted(QSInv) then
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
elseif isStarted(QBInv) then elseif isStarted(QBInv) then
if QBInvNew then if QBInvNew then
TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop) TriggerServerEvent(getScript()..':server:OpenShopNewQB', data.shop)
else else
TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items) TriggerServerEvent("inventory:server:OpenInventory", "shop", data.items.label, data.items)
end end
elseif isStarted(RSGInv) then elseif isStarted(RSGInv) then
TriggerServerEvent(getScript()..':server:OpenShopNewRSG', data.shop) TriggerServerEvent(getScript()..':server:OpenShopNewRSG', data.shop)
end end

View File

@@ -322,7 +322,7 @@ function stashRemoveItem(stashItems, stashName, items)
stashItems[l] = nil stashItems[l] = nil
else else
debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v) debugPrint("^6Bridge^7: ^2Removing item from ^3Stash^2 with ^7"..QBInv, k, v)
exports[QSInv]:RemoveItemIntoStash(stashName, k, v, l) exports[QSInv]:RemoveItemIntoStash(stashName[1], k, v, l)
end end
end end
end end
@@ -350,6 +350,7 @@ function stashRemoveItem(stashItems, stashName, items)
end end
exports[CodeMInv]:UpdateStash(stashName, stashItems) exports[CodeMInv]:UpdateStash(stashName, stashItems)
debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3CodeM^2 stash ^7'^6"..stashName.."^7'") debugPrint("^6Bridge^7: ^3saveStash^7: ^2Saving ^3CodeM^2 stash ^7'^6"..stashName.."^7'")
elseif isStarted(OrigenInv) then elseif isStarted(OrigenInv) then
for k, v in pairs(items) do for k, v in pairs(items) do
exports[OrigenInv]:RemoveFromStash(stashName, k, v) exports[OrigenInv]:RemoveFromStash(stashName, k, v)

View File

@@ -61,7 +61,7 @@ function registerStash(name, label, slots, weight, owner, coords)
exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil) exports[OXInv]:RegisterStash(name, label, slots or 50, weight or 4000000, owner or nil)
elseif isStarted(QSInv) then elseif isStarted(QSInv) then
debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label) debugPrint("^6Bridge^7: ^2Registering ^3QS ^2Stash^7:", name, label)
exports[QSInv]:RegisterStash(nil, name, slots or 50, weight or 4000000) exports[QSInv]:RegisterStash(name, label, slots or 50, weight or 4000000)
--elseif isStarted(CoreInv) then --elseif isStarted(CoreInv) then
-- debugPrint("^6Bridge^7: ^2Registering ^3CoreInv ^2Stash^7:", name, label) -- debugPrint("^6Bridge^7: ^2Registering ^3CoreInv ^2Stash^7:", name, label)

View File

@@ -1 +1 @@
2.0.01 2.0.03