This commit is contained in:
Insality
2025-10-27 01:15:57 +02:00
parent 1f1438b4af
commit f3f19337a3
7 changed files with 83 additions and 161 deletions

View File

@@ -3,54 +3,10 @@
local installer = require("druid.editor_scripts.core.installer") local installer = require("druid.editor_scripts.core.installer")
local ui_components = require("druid.editor_scripts.core.ui_components") local ui_components = require("druid.editor_scripts.core.ui_components")
local internal = require("druid.editor_scripts.core.asset_store_internal")
local M = {} local M = {}
local STORE_URL = "https://insality.github.io/core/druid_widget_store.json"
---Fetch widget data from the remote store
---@return table|nil, string|nil - Store data or nil, error message or nil
local function fetch_store_data()
print("Fetching widget data from:", STORE_URL)
local response = http.request(STORE_URL, {
as = "json"
})
if response.status ~= 200 then
return nil, "Failed to fetch store data. HTTP status: " .. response.status
end
if not response.body or not response.body.items then
return nil, "Invalid store data format"
end
print("Successfully fetched", #response.body.items, "widgets")
return response.body, nil
end
---Filter items based on author and tag filters
---@param items table - List of widget items
---@param author_filter string - Author filter value
---@param tag_filter string - Tag filter value
---@return table - Filtered list of items
local function filter_items(items, author_filter, tag_filter)
local filtered = {}
for _, item in ipairs(items) do
local author_match = author_filter == "All Authors" or item.author == author_filter
local tag_match = tag_filter == "All Categories" or (item.tags and table.concat(item.tags, ","):find(tag_filter))
if author_match and tag_match then
table.insert(filtered, item)
end
end
return filtered
end
---Handle widget installation ---Handle widget installation
---@param item table - Widget item to install ---@param item table - Widget item to install
@@ -116,37 +72,25 @@ end
---Open the asset store dialog ---Open the asset store dialog
function M.open_asset_store() function M.open_asset_store(store_url)
print("Opening Druid Asset Store") print("Opening Druid Asset Store from:", store_url)
-- Fetch data synchronously before creating the dialog -- Fetch data synchronously before creating the dialog
local store_data, fetch_error = fetch_store_data() local store_data, fetch_error = internal.download_json(store_url)
local initial_items = {} if not store_data then
local initial_loading = false
local initial_error = nil
if store_data then
initial_items = store_data.items
print("Successfully loaded", #initial_items, "widgets")
else
initial_error = fetch_error
print("Failed to load widgets:", fetch_error) print("Failed to load widgets:", fetch_error)
return
end end
print("Successfully loaded", #store_data.items, "widgets")
local initial_items = store_data.items
local dialog_component = editor.ui.component(function(props) local dialog_component = editor.ui.component(function(props)
editor.prefs.set("druid.asset_install_folder", "/widget")
-- State management -- State management
local items, set_items = editor.ui.use_state(initial_items) local items, set_items = editor.ui.use_state(initial_items)
local loading, set_loading = editor.ui.use_state(initial_loading)
local error_message, set_error_message = editor.ui.use_state(initial_error)
local install_folder, set_install_folder = editor.ui.use_state(editor.prefs.get("druid.asset_install_folder") or installer.get_default_install_folder()) local install_folder, set_install_folder = editor.ui.use_state(editor.prefs.get("druid.asset_install_folder") or installer.get_default_install_folder())
local author_filter, set_author_filter = editor.ui.use_state("All Authors") local search_query, set_search_query = editor.ui.use_state("")
local tag_filter, set_tag_filter = editor.ui.use_state("All Categories")
local install_status, set_install_status = editor.ui.use_state("") local install_status, set_install_status = editor.ui.use_state("")
-- Filter items
local filtered_items = editor.ui.use_memo(filter_items, items, author_filter, tag_filter)
-- Installation status check function -- Installation status check function
local function is_widget_installed(item) local function is_widget_installed(item)
return installer.is_widget_installed(item, install_folder) return installer.is_widget_installed(item, install_folder)
@@ -174,27 +118,43 @@ function M.open_asset_store()
local content_children = {} local content_children = {}
-- Settings section -- Settings section
table.insert(content_children, editor.ui.label({ table.insert(content_children, editor.ui.horizontal({
spacing = editor.ui.SPACING.MEDIUM, spacing = editor.ui.SPACING.MEDIUM,
text = "Installation Folder: " .. install_folder, children = {
editor.ui.label({
spacing = editor.ui.SPACING.MEDIUM,
text = "Installation Folder:",
color = editor.ui.COLOR.TEXT color = editor.ui.COLOR.TEXT
}),
editor.ui.string_field({
value = install_folder,
on_value_changed = set_install_folder,
title = "Installation Folder:",
tooltip = "The folder to install the assets to",
}),
}
})) }))
-- Filter section (only show if we have items) -- Search section
if #items > 0 then table.insert(content_children, editor.ui.horizontal({
table.insert(content_children, editor.ui.label({
spacing = editor.ui.SPACING.MEDIUM, spacing = editor.ui.SPACING.MEDIUM,
text = "Filters: Author: " .. author_filter .. ", Category: " .. tag_filter, children = {
editor.ui.label({
text = "Search:",
color = editor.ui.COLOR.TEXT color = editor.ui.COLOR.TEXT
}),
editor.ui.string_field({
value = search_query,
on_value_changed = set_search_query,
title = "Search:",
tooltip = "Search for widgets by title, author, or description",
})
},
})) }))
end
-- Main content area -- Main content area
if loading then if #items == 0 then
table.insert(content_children, ui_components.create_loading_indicator("Loading widget store..."))
elseif error_message then
table.insert(content_children, ui_components.create_error_message(error_message))
elseif #filtered_items == 0 then
table.insert(content_children, editor.ui.label({ table.insert(content_children, editor.ui.label({
text = "No widgets found matching the current filters.", text = "No widgets found matching the current filters.",
color = editor.ui.COLOR.HINT, color = editor.ui.COLOR.HINT,
@@ -202,7 +162,7 @@ function M.open_asset_store()
})) }))
else else
table.insert(content_children, ui_components.create_widget_list( table.insert(content_children, ui_components.create_widget_list(
filtered_items, is_widget_installed, on_install, on_open_api items, is_widget_installed, on_install, on_open_api
)) ))
end end
@@ -219,7 +179,7 @@ function M.open_asset_store()
title = "Druid Asset Store", title = "Druid Asset Store",
content = editor.ui.vertical({ content = editor.ui.vertical({
spacing = editor.ui.SPACING.SMALL, spacing = editor.ui.SPACING.SMALL,
padding = editor.ui.PADDING.NONE, padding = editor.ui.PADDING.SMALL,
children = content_children children = content_children
}), }),
buttons = { buttons = {
@@ -231,11 +191,7 @@ function M.open_asset_store()
}) })
end) end)
local result = editor.ui.show_dialog(dialog_component({})) return editor.ui.show_dialog(dialog_component({}))
-- Save the install folder preference (this will be handled by the state management in the dialog)
return result
end end

View File

@@ -0,0 +1,21 @@
local M = {}
---Download a JSON file from a URL
---@param json_url string - The URL to download the JSON from
---@return table|nil, string|nil - The JSON data or nil, error message or nil
function M.download_json(json_url)
local response = http.request(json_url, { as = "json" })
if response.status ~= 200 then
return nil, "Failed to fetch store data. HTTP status: " .. response.status
end
if not response.body or not response.body.items then
return nil, "Invalid store data format"
end
return response.body, nil
end
return M

View File

@@ -1,8 +1,8 @@
local base64 = require("druid.editor_scripts.core.base64")
local path_replacer = require("druid.editor_scripts.core.path_replacer")
--- Module for handling widget installation from zip files --- Module for handling widget installation from zip files
--- Downloads zip files and extracts them to the specified folder --- Downloads zip files and extracts them to the specified folder
local base64 = require("druid.editor_scripts.core.base64")
local M = {} local M = {}
local DEFAULT_INSTALL_FOLDER = "/widget" local DEFAULT_INSTALL_FOLDER = "/widget"
@@ -79,14 +79,13 @@ function M.install_widget(item, install_folder)
print("Zip file removed successfully") print("Zip file removed successfully")
-- Process paths within the extracted widget -- Process paths within the extracted widget
local files_in_folder = path_replacer.get_all_files(folder_path) --local files_in_folder = path_replacer.get_all_files(folder_path)
pprint(files_in_folder) --pprint(files_in_folder)
--if not path_replacer.process_widget_paths(install_folder .. "/" .. folder_name, new_base_path) then --if not path_replacer.process_widget_paths(install_folder .. "/" .. folder_name, new_base_path) then
-- return false, "Failed to process widget paths" -- return false, "Failed to process widget paths"
--end --end
return true, "Widget installed successfully" return true, "Widget installed successfully"
end end
@@ -96,8 +95,8 @@ end
---@param install_folder string - Install folder to check in ---@param install_folder string - Install folder to check in
---@return boolean - True if widget is already installed ---@return boolean - True if widget is already installed
function M.is_widget_installed(item, install_folder) function M.is_widget_installed(item, install_folder)
-- For now, assume widgets are not installed to avoid path issues local p = editor.resource_attributes(install_folder .. "/" .. item.id)
return false return p.exists
end end

View File

@@ -1,22 +0,0 @@
--- Module for replacing paths in extracted widget files
--- Handles updating require statements and file paths to match the installation location
local M = {}
---Recursively get all files in a directory
---@param dir_path string - Directory path to scan
---@param extension string|nil - Optional file extension filter (e.g., ".lua")
---@return string[] - List of file paths
function M.get_all_files(dir_path, extension)
local attributes = editor.resource_attributes(dir_path)
local files = io.popen("ls -R " .. dir_path)
for line in files:lines() do
print(line)
end
pprint(files)
return files
end
return M

View File

@@ -162,9 +162,12 @@ function M.create_widget_item(item, is_installed, on_install, on_open_api)
end end
return editor.ui.horizontal({ return editor.ui.horizontal({
spacing = editor.ui.SPACING.MEDIUM, spacing = editor.ui.SPACING.NONE,
padding = editor.ui.PADDING.MEDIUM, padding = editor.ui.PADDING.SMALL,
children = { children = {
editor.ui.separator({
orientation = editor.ui.ORIENTATION.HORIZONTAL,
}),
-- Widget icon placeholder -- Widget icon placeholder
editor.ui.label({ editor.ui.label({
text = "📦", text = "📦",
@@ -227,12 +230,13 @@ function M.create_widget_item(item, is_installed, on_install, on_open_api)
-- Action buttons -- Action buttons
editor.ui.vertical({ editor.ui.vertical({
spacing = editor.ui.SPACING.SMALL, spacing = editor.ui.SPACING.MEDIUM,
children = { children = {
editor.ui.button({ editor.ui.button({
text = is_installed and "Reinstall" or "Install",
text = "Install",
on_pressed = on_install, on_pressed = on_install,
enabled = true enabled = is_installed == false
}), }),
editor.ui.button({ editor.ui.button({
text = "API", text = "API",
@@ -240,7 +244,7 @@ function M.create_widget_item(item, is_installed, on_install, on_open_api)
enabled = item.api ~= nil enabled = item.api ~= nil
}) })
} }
}) }),
} }
}) })
end end
@@ -274,40 +278,4 @@ function M.create_widget_list(items, is_installed_func, on_install, on_open_api)
end end
---Create a loading indicator
---@param message string - Loading message
---@return userdata - UI component
function M.create_loading_indicator(message)
return editor.ui.vertical({
spacing = editor.ui.SPACING.MEDIUM,
alignment = editor.ui.ALIGNMENT.CENTER,
children = {
editor.ui.label({
text = message or "Loading...",
color = editor.ui.COLOR.TEXT,
alignment = editor.ui.ALIGNMENT.CENTER
})
}
})
end
---Create an error message display
---@param message string - Error message
---@return userdata - UI component
function M.create_error_message(message)
return editor.ui.vertical({
spacing = editor.ui.SPACING.MEDIUM,
alignment = editor.ui.ALIGNMENT.CENTER,
children = {
editor.ui.label({
text = "Error: " .. message,
color = editor.ui.COLOR.ERROR,
alignment = editor.ui.ALIGNMENT.CENTER
})
}
})
end
return M return M

View File

@@ -74,7 +74,7 @@ function M.get_commands()
label = "[Druid] Asset Store", label = "[Druid] Asset Store",
locations = { "Edit" }, locations = { "Edit" },
run = function() run = function()
return asset_store.open_asset_store() return asset_store.open_asset_store("https://insality.github.io/core/druid_widget_store.json")
end end
}, },