added new scripts and eup

This commit is contained in:
KingMcDonalds
2025-05-19 16:45:39 -07:00
parent 92357c972e
commit 5fa9cc69be
292 changed files with 10254 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
# LICENSE
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-nd/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>.
+47
View File
@@ -0,0 +1,47 @@
xMenu = {}
xMenu.__index = xMenu
function xMenu.New(name, color)
local newMenu = {}
setmetatable(newMenu, xMenu)
newMenu.Name = name
newMenu.Resource = GetCurrentResourceName()
newMenu.Handle = exports["xmenu"]:AddMenu(name, newMenu.Resource)
newMenu.Color = color
return newMenu
end
function xMenu:IsAnyMenuOpen()
return exports["xmenu"]:IsAnyMenuOpen()
end
function xMenu:OpenMenu()
exports["xmenu"]:OpenMenu(self.Handle, self.Color)
end
function xMenu:CloseMenu()
exports["xmenu"]:CloseMenu()
end
function xMenu:BindSubMenu(name)
local newHandle = exports["xmenu"]:AddSubMenu(name, self.Handle, self.Resource)
return xSubMenu.New(name, newHandle)
end
function xMenu:BindButton(name, callback)
exports["xmenu"]:AddButton(name, self.Handle, callback, self.Resource)
end
function xMenu:BindCheckbox(name, state, callback)
exports["xmenu"]:AddCheckbox(name, state, self.Handle, callback, self.Resource)
end
function xMenu:BindList(name, list, callback)
exports["xmenu"]:AddList(name, self.Handle, list, callback, self.Resource)
end
function xMenu:ClearMenu()
exports["xmenu"]:ClearMenu(self.Handle)
end
+30
View File
@@ -0,0 +1,30 @@
xSubMenu = {}
xSubMenu.__index = xMenu
function xSubMenu.New(name, handle)
local newMenu = {}
setmetatable(newMenu, xMenu)
newMenu.Name = name
newMenu.Handle = handle
newMenu.Resource = GetCurrentResourceName()
return newMenu
end
function xSubMenu:BindSubMenu(name)
local newHandle = exports["xmenu"]:AddSubMenu(name, self.Handle, self.Resource)
return xSubMenu.New(name, newHandle)
end
function xMenu:BindButton(name, callback)
exports["xmenu"]:AddButton(name, self.Handle, callback, self.Resource)
end
function xMenu:BindCheckbox(name, state, callback)
exports["xmenu"]:AddCheckbox(name, state, self.Handle, callback, self.Resource)
end
function xMenu:BindList(name, list, callback)
exports["xmenu"]:AddList(name, self.Handle, list, callback, self.Resource)
end
+347
View File
@@ -0,0 +1,347 @@
-- All Data
local Menus = {}
local Components = {}
local Resources = {}
-- Current Data
local OpenedMenu = nil
local HoveredIndex = 1
function IsResourceStarted(resource)
for _, v in pairs(Resources) do
if v == resource then
return true
end
end
return false
end
function AddMenu(name, resource)
local index = Utils.GenerateUUID()
table.insert(Resources, resource)
Menus[index] = {
name = name,
type = "base",
components = {},
resource = resource
}
return index
end
function AddSubMenu(name, menu, resource)
local index = Utils.GenerateUUID()
Menus[index] = {
name = name,
type = "submenu",
components = {},
parent = menu,
resource = resource
}
table.insert(Menus[menu].components, {
index = index,
name = name,
parent = menu,
type = "submenu",
resource = resource
})
return index
end
function AddButton(name, menu, callback, resource)
local index = Utils.GenerateUUID()
Components[index] = {
name = name,
type = "button",
action = callback,
resource = resource
}
table.insert(Menus[menu].components, {
index = index,
name = name,
type = "button"
})
end
function AddCheckbox(name, state, menu, callback, resource)
local index = Utils.GenerateUUID()
Components[index] = {
name = name,
type = "checkbox",
action = callback,
state = state,
resource = resource
}
table.insert(Menus[menu].components, {
index = index,
name = name,
type = "checkbox",
state = state
})
end
function AddList(name, menu, list, callback, resource)
local index = Utils.GenerateUUID()
Components[index] = {
name = name,
type = "list",
action = callback,
list = list,
listIndex = 1,
resource = resource
}
table.insert(Menus[menu].components, {
index = index,
name = name,
type = "list",
list = list,
listIndex = 1
})
end
function OpenMenu(menu, color)
local menuToOpen = Menus[menu]
if menuToOpen then
SendNUIMessage({
type = "open_menu",
data = {
name = menuToOpen.name,
components = menuToOpen.components,
option = 1,
color = color
}
})
OpenedMenu = menuToOpen
HoveredIndex = 1
end
end
function CloseMenu()
if OpenedMenu then
SendNUIMessage({ type = "close_menu" })
OpenedMenu = nil
HoveredIndex = 1
end
end
function IsAnyMenuOpen()
if OpenedMenu then
return true
end
return false
end
function IsMenuOpened(menu)
if OpenedMenu.index == menu then
return true
end
return false
end
function GetOpenedMenu()
if OpenedMenu then
return OpenedMenu.index
end
return nil
end
function ClearMenu(menu)
for k, v in pairs(Menus[menu].components) do
local index = v.index
for a = 1, #Components do
table.remove(Components, index, 1)
end
table.remove(Menus[menu].components, k, 1)
end
end
-- EXPORTS
exports("AddMenu", AddMenu)
exports("AddSubMenu", AddSubMenu)
exports("AddButton", AddButton)
exports("OpenMenu", OpenMenu)
exports("AddCheckbox", AddCheckbox)
exports("AddList", AddList)
exports("CloseMenu", CloseMenu)
exports("IsAnyMenuOpen", IsAnyMenuOpen)
exports("IsMenuOpen", IsMenuOpened)
exports("GetOpenedMenu", GetOpenedMenu)
exports("ClearMenu", ClearMenu)
-- EVENTS
AddEventHandler("onResourceStop", function(resource)
if resource == GetCurrentResourceName() then return end
if not IsResourceStarted(resource) then return end
for k, v in pairs(Menus) do
if v.resource == resource then
Menus[k] = nil
end
end
for k, v in pairs(Components) do
if v.resource == resource then
Components[k] = nil
end
end
for k, v in pairs(Resources) do
if v == resource then
Resources[k] = nil
end
end
end)
-- CONTROLS
function GoUp()
local prev = HoveredIndex - 1
if prev < 1 then
prev = #OpenedMenu.components
end
HoveredIndex = prev
SendNUIMessage({
type = "set_menu_option",
data = {
option = HoveredIndex
}
})
end
function GoDown()
local next = HoveredIndex + 1
if next > #OpenedMenu.components then
next = 1
end
HoveredIndex = next
SendNUIMessage({
type = "set_menu_option",
data = {
option = HoveredIndex
}
})
end
function GoLeft()
local selected = OpenedMenu.components[HoveredIndex]
if selected then
if selected.type == "list" then
local comp = Components[selected.index]
local next = selected.listIndex - 1
if next < 1 then
next = #selected.list
end
selected.listIndex = next
comp.listIndex = next
SendNUIMessage({
type = "set_list_item",
data = {
index = selected.index,
listIndex = next
}
})
end
end
end
function GoRight()
local selected = OpenedMenu.components[HoveredIndex]
if selected then
if selected.type == "list" then
local comp = Components[selected.index]
local next = selected.listIndex + 1
if next > #selected.list then
next = 1
end
selected.listIndex = next
comp.listIndex = next
SendNUIMessage({
type = "set_list_item",
data = {
index = selected.index,
listIndex = next
}
})
end
end
end
function Enter()
local selected = OpenedMenu.components[HoveredIndex]
if selected then
if selected.type == "submenu" then
OpenMenu(selected.index)
else
local component = Components[selected.index]
if selected.type == "checkbox" then
local newState = not component.state
component.state = newState
selected.state = newState
component.action(newState)
SendNUIMessage({
type = "set_checkbox_state",
data = {
id = selected.index,
state = newState
}
})
elseif selected.type == "list" then
local comp = Components[selected.index]
comp.action(comp.list[comp.listIndex])
elseif selected.type == "button" then
Components[selected.index].action()
end
end
end
end
function Backspace()
if OpenedMenu then
if not OpenedMenu.parent then
CloseMenu()
else
OpenMenu(OpenedMenu.parent)
end
end
end
Citizen.CreateThread(function()
while true do
Citizen.Wait(0)
if OpenedMenu then
if IsControlJustPressed(0, 172) then
GoUp()
elseif IsControlJustPressed(0, 173) then
GoDown()
elseif IsControlJustPressed(0, 174) then
GoLeft()
elseif IsControlJustPressed(0, 175) then
GoRight()
elseif IsControlJustPressed(0, 176) then
Enter()
elseif IsControlJustPressed(0, 177) then
Backspace()
end
end
end
end)
+30
View File
@@ -0,0 +1,30 @@
-- local menu = xMenu.New("MyMenuName")
-- local submenu = menu:BindSubMenu("SubMenuName")
-- menu:BindButton("ButtonName", function()
-- print("TRIGGERED!")
-- end)
-- menu:BindCheckbox("Checkbox", function(state)
-- print("STATE: " .. tostring(state))
-- end)
-- submenu:BindButton("ButtonName", function()
-- print("TRIGGERED!")
-- end)
-- submenu:BindList("ListHere", { "1", "2" }, function()
-- print("LIST CALLED!")
-- end)
-- Citizen.CreateThread(function()
-- while true do
-- Citizen.Wait(0)
-- if IsControlJustPressed(0, 121) then
-- if not menu:IsAnyMenuOpen() then
-- menu:OpenMenu()
-- end
-- end
-- end
-- end)
+21
View File
@@ -0,0 +1,21 @@
fx_version 'adamant'
game 'gta5'
name 'FiveM NUI Menu Manager'
description 'An NUI menu manager for FiveM'
author 'Xander1998'
url 'https://github.com/xander1998/xmenu'
ui_page("html/index.html")
files {
"html/index.html",
"html/events.js",
"html/script.js",
"html/style.css"
}
client_script "classes/*.lua"
client_script "utils.lua"
client_script "menu.lua"
client_script "client.lua"
client_script "example.lua"
+17
View File
@@ -0,0 +1,17 @@
const EVENTS = []
document.onreadystatechange = () => {
if (document.readyState == "complete") {
window.addEventListener("message", (event) => {
EVENTS.forEach(e => {
if (e.event == event.data.type) {
e.callback(event.data.data);
}
});
})
}
}
function RegisterEvent(event, callback) {
EVENTS.push({ event, callback });
}
+51
View File
@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>XMenu</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app" v-show="visible">
<div id="menu_base" class="middle-right">
<div id="menu_header" v-bind:style="{ 'background-color': HeaderColor }">
{{ MenuName }}
</div>
<div id="menu_body">
<div v-for="(comp, compIndex) in MenuComponents">
<!-- List -->
<div :id="compIndex" v-if="comp.type == 'list'" class="menu_button" v-bind:class="{ 'menu_button_hovered': compIndex == MenuOption }">
<i class="fa fa-arrow-left fa-2x menu_list_icon_left"></i>
{{ comp.list[comp.listIndex - 1] }}
<i class="fa fa-arrow-right fa-2x menu_list_icon_right"></i>
</div>
<!-- Checkbox -->
<div :id="compIndex" v-else-if="comp.type == 'checkbox'" class="menu_checkbox" v-bind:class="{ 'menu_checkbox_hovered': compIndex == MenuOption, 'menu_checkbox_icon_hovered': compIndex == MenuOption }">
{{ comp.name }}
<i v-if="comp.state" class="fa fa-check-square fa-2x menu_checkbox_icon"></i>
<i v-else class="fa fa-square fa-2x menu_checkbox_icon"></i>
</div>
<!-- Button -->
<div :id="compIndex" v-else class="menu_button" v-bind:class="{ 'menu_button_hovered': compIndex == MenuOption }">
{{ comp.name }}
</div>
</div>
</div>
</div>
</div>
<script src="https://use.fontawesome.com/4802736edb.js"></script>
<script src="https://use.fontawesome.com/4802736edb.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- DEVELOPMENT -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.11"></script> --> <!-- PRODUCTION -->
<script src="events.js"></script>
<script src="script.js"></script>
</body>
</html>
+65
View File
@@ -0,0 +1,65 @@
const app = new Vue({
el: "#app",
data: {
resource: "xmenu",
visible: false,
// Menu
MenuName: "Default",
MenuComponents: {},
MenuOption: 0,
HeaderColor: "#0984e3"
},
methods: {
SetResourceData(data) {
this.resource = data.resource;
},
OpenMenu(data) {
this.MenuName = data.name;
this.MenuComponents = data.components;
this.MenuOption = data.option - 1;
this.HeaderColor = data.color || "#0984e3";
this.visible = true;
},
CloseMenu() {
this.MenuName = "";
this.MenuComponents = {};
this.MenuOption = 0;
this.visible = false;
},
SetMenuOption(data) {
this.MenuOption = data.option - 1;
const element = document.getElementById(`${this.MenuOption}`);
element.scrollIntoView();
},
SetCheckboxState(data) {
const comp = this.GetMenuIndexById(data.id)
if (comp != null) {
this.MenuComponents[comp].state = data.state
}
},
SetListItem(data) {
this.MenuComponents.forEach(comp => {
if (comp.index == data.index) {
comp.listIndex = data.listIndex
}
});
},
GetMenuIndexById(id) {
for (let a = 0; a < this.MenuComponents.length; a++) {
if (this.MenuComponents[a].index == id) {
return a
}
}
return null;
}
},
mounted() {
RegisterEvent("set_resource_data", this.SetResourceData);
RegisterEvent("open_menu", this.OpenMenu);
RegisterEvent("close_menu", this.CloseMenu);
RegisterEvent("set_menu_option", this.SetMenuOption);
RegisterEvent("set_checkbox_state", this.SetCheckboxState);
RegisterEvent("set_list_item", this.SetListItem);
}
})
+131
View File
@@ -0,0 +1,131 @@
:root {
/* Vars */
--header-font-size: 20px;
/* Colors */
--blue: #0984e3;
--white: white;
--midgray: #636e72;
--darkgray: #2d3436;
--red: red;
--black: #000000;
}
html {
overflow: hidden;
}
body {
margin: 0;
}
#app {
width: 100%;
height: 100%;
}
#menu_base {
position: absolute;
width: 20%;
position: absolute;
font-family: Verdana, Geneva, Tahoma, sans-serif;
background-color: var(--darkgray);
}
#menu_header {
font-size: var(--menu-header-font-size);
padding: 15px;
text-align: center;
color: white;
}
#menu_body {
position: relative;
margin: 1px;
max-height: 500px;
overflow-y: auto;
}
/* BUTTON CLASSES */
.menu_button {
padding: 12px;
text-align: center;
background-color: var(--black);
color: white;
border-style: solid;
border-width: 1px;
border-color: var(--white);
margin: 5px;
}
.menu_button_hovered {
background-color: var(--white) !important;
border-style: solid;
border-width: 1px;
border-color: var(--black);
color: var(--black);
}
/* CHECKBOX CLASSES */
.menu_checkbox {
padding: 12px;
text-align: center;
background-color: var(--black);
color: white;
border-style: solid;
border-width: 1px;
border-color: var(--white);
margin: 5px;
}
.menu_checkbox_hovered {
background-color: var(--white) !important;
border-style: solid;
border-width: 1px;
border-color: var(--black);
color: var(--black);
}
.menu_checkbox_icon {
position: absolute;
right: 25px;
margin-top: -6px;
}
/* LIST CLASSES */
.menu_list_icon_left {
position: absolute;
left: 25px;
margin-top: -6px;
}
.menu_list_icon_right {
position: absolute;
right: 25px;
margin-top: -6px;
}
/* POSITION CLASSES */
.top-left {
top: 5px;
left: 5px;
}
.top-right {
top: 5px;
right: 5px;
}
.middle-left {
top: 50%;
left: 5px;
transform: translateY(-50%);
}
.middle-right {
top: 50%;
right: 5px;
transform: translateY(-50%);
}
.bottom-left {
bottom: 5px;
left: 5px;
}
.bottom-right {
bottom: 5px;
right: 5px;
}
+9
View File
@@ -0,0 +1,9 @@
Utils = {}
function Utils.GenerateUUID()
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
return string.gsub(template, '[xy]', function (c)
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
return string.format('%x', v)
end)
end