mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-25 14:25:02 +00:00
359 lines
9.8 KiB
Lua
359 lines
9.8 KiB
Lua
-- css_designer/seed/scripts/db/operations.lua
|
|
-- DBAL operations for Theme and Style entities
|
|
-- @module css_designer.db.operations
|
|
|
|
local M = {}
|
|
local json = require('json')
|
|
|
|
---------------------------------------------------------------------------
|
|
-- THEME OPERATIONS
|
|
---------------------------------------------------------------------------
|
|
|
|
---@class ThemeCreateParams
|
|
---@field tenantId string
|
|
---@field name string
|
|
---@field baseTheme string|nil ('light', 'dark', or parent theme ID)
|
|
---@field variables table CSS variable definitions
|
|
---@field metadata table|nil
|
|
|
|
---Create a new theme
|
|
---@param dbal table DBAL client instance
|
|
---@param params ThemeCreateParams
|
|
---@return table Created theme
|
|
function M.createTheme(dbal, params)
|
|
return dbal:create('Theme', {
|
|
tenantId = params.tenantId,
|
|
name = params.name,
|
|
baseTheme = params.baseTheme or 'light',
|
|
variables = json.encode(params.variables),
|
|
metadata = params.metadata and json.encode(params.metadata) or nil,
|
|
isActive = true,
|
|
version = 1,
|
|
createdAt = os.time() * 1000,
|
|
updatedAt = os.time() * 1000,
|
|
})
|
|
end
|
|
|
|
---Get theme by ID
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@return table|nil Theme with decoded variables
|
|
function M.getTheme(dbal, themeId)
|
|
local theme = dbal:read('Theme', themeId)
|
|
if theme then
|
|
theme.variables = json.decode(theme.variables or '{}')
|
|
if theme.metadata then
|
|
theme.metadata = json.decode(theme.metadata)
|
|
end
|
|
end
|
|
return theme
|
|
end
|
|
|
|
---Get theme by name
|
|
---@param dbal table
|
|
---@param tenantId string
|
|
---@param name string
|
|
---@return table|nil Theme
|
|
function M.getThemeByName(dbal, tenantId, name)
|
|
local theme = dbal:findFirst('Theme', {
|
|
where = { tenantId = tenantId, name = name },
|
|
})
|
|
if theme then
|
|
theme.variables = json.decode(theme.variables or '{}')
|
|
end
|
|
return theme
|
|
end
|
|
|
|
---List themes for tenant
|
|
---@param dbal table
|
|
---@param tenantId string
|
|
---@param activeOnly boolean|nil
|
|
---@return table[] Themes
|
|
function M.listThemes(dbal, tenantId, activeOnly)
|
|
local where = { tenantId = tenantId }
|
|
if activeOnly then
|
|
where.isActive = true
|
|
end
|
|
|
|
local result = dbal:list('Theme', {
|
|
where = where,
|
|
orderBy = { name = 'asc' },
|
|
take = 50,
|
|
})
|
|
|
|
return result.items or {}
|
|
end
|
|
|
|
---Update theme
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@param updates table
|
|
---@return table Updated theme
|
|
function M.updateTheme(dbal, themeId, updates)
|
|
if updates.variables and type(updates.variables) == 'table' then
|
|
updates.variables = json.encode(updates.variables)
|
|
-- Increment version on variable changes
|
|
local theme = M.getTheme(dbal, themeId)
|
|
if theme then
|
|
updates.version = (theme.version or 1) + 1
|
|
end
|
|
end
|
|
if updates.metadata and type(updates.metadata) == 'table' then
|
|
updates.metadata = json.encode(updates.metadata)
|
|
end
|
|
updates.updatedAt = os.time() * 1000
|
|
return dbal:update('Theme', themeId, updates)
|
|
end
|
|
|
|
---Set theme variable
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@param varName string CSS variable name
|
|
---@param value string Value
|
|
function M.setVariable(dbal, themeId, varName, value)
|
|
local theme = M.getTheme(dbal, themeId)
|
|
if not theme then
|
|
error('Theme not found: ' .. themeId)
|
|
end
|
|
|
|
local vars = theme.variables or {}
|
|
vars[varName] = value
|
|
|
|
return M.updateTheme(dbal, themeId, { variables = vars })
|
|
end
|
|
|
|
---Clone theme
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@param newName string
|
|
---@return table Cloned theme
|
|
function M.cloneTheme(dbal, themeId, newName)
|
|
local original = M.getTheme(dbal, themeId)
|
|
if not original then
|
|
error('Theme not found: ' .. themeId)
|
|
end
|
|
|
|
return M.createTheme(dbal, {
|
|
tenantId = original.tenantId,
|
|
name = newName,
|
|
baseTheme = original.baseTheme,
|
|
variables = original.variables,
|
|
metadata = original.metadata,
|
|
})
|
|
end
|
|
|
|
---Delete theme
|
|
---@param dbal table
|
|
---@param themeId string
|
|
function M.deleteTheme(dbal, themeId)
|
|
return dbal:delete('Theme', themeId)
|
|
end
|
|
|
|
---------------------------------------------------------------------------
|
|
-- STYLE COMPONENT OPERATIONS
|
|
---------------------------------------------------------------------------
|
|
|
|
---@class StyleComponentParams
|
|
---@field tenantId string
|
|
---@field themeId string|nil
|
|
---@field name string
|
|
---@field selector string CSS selector
|
|
---@field styles table CSS properties
|
|
---@field variants table|nil Style variants
|
|
|
|
---Create style component
|
|
---@param dbal table
|
|
---@param params StyleComponentParams
|
|
---@return table Created component
|
|
function M.createComponent(dbal, params)
|
|
return dbal:create('StyleComponent', {
|
|
tenantId = params.tenantId,
|
|
themeId = params.themeId,
|
|
name = params.name,
|
|
selector = params.selector,
|
|
styles = json.encode(params.styles),
|
|
variants = params.variants and json.encode(params.variants) or nil,
|
|
createdAt = os.time() * 1000,
|
|
updatedAt = os.time() * 1000,
|
|
})
|
|
end
|
|
|
|
---Get component by ID
|
|
---@param dbal table
|
|
---@param componentId string
|
|
---@return table|nil Component
|
|
function M.getComponent(dbal, componentId)
|
|
local comp = dbal:read('StyleComponent', componentId)
|
|
if comp then
|
|
comp.styles = json.decode(comp.styles or '{}')
|
|
if comp.variants then
|
|
comp.variants = json.decode(comp.variants)
|
|
end
|
|
end
|
|
return comp
|
|
end
|
|
|
|
---List components for theme
|
|
---@param dbal table
|
|
---@param themeId string|nil
|
|
---@param tenantId string
|
|
---@return table[] Components
|
|
function M.listComponents(dbal, tenantId, themeId)
|
|
local where = { tenantId = tenantId }
|
|
if themeId then
|
|
where.themeId = themeId
|
|
end
|
|
|
|
local result = dbal:list('StyleComponent', {
|
|
where = where,
|
|
orderBy = { name = 'asc' },
|
|
take = 200,
|
|
})
|
|
|
|
return result.items or {}
|
|
end
|
|
|
|
---Update component styles
|
|
---@param dbal table
|
|
---@param componentId string
|
|
---@param styles table CSS properties
|
|
function M.updateStyles(dbal, componentId, styles)
|
|
return dbal:update('StyleComponent', componentId, {
|
|
styles = json.encode(styles),
|
|
updatedAt = os.time() * 1000,
|
|
})
|
|
end
|
|
|
|
---Delete component
|
|
---@param dbal table
|
|
---@param componentId string
|
|
function M.deleteComponent(dbal, componentId)
|
|
return dbal:delete('StyleComponent', componentId)
|
|
end
|
|
|
|
---------------------------------------------------------------------------
|
|
-- CSS GENERATION
|
|
---------------------------------------------------------------------------
|
|
|
|
---Generate CSS variables from theme
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@return string CSS custom properties
|
|
function M.generateVariablesCSS(dbal, themeId)
|
|
local theme = M.getTheme(dbal, themeId)
|
|
if not theme then
|
|
return ''
|
|
end
|
|
|
|
local css = ':root {\n'
|
|
for name, value in pairs(theme.variables or {}) do
|
|
css = css .. ' --' .. name .. ': ' .. value .. ';\n'
|
|
end
|
|
css = css .. '}\n'
|
|
|
|
return css
|
|
end
|
|
|
|
---Generate CSS for all components
|
|
---@param dbal table
|
|
---@param tenantId string
|
|
---@param themeId string|nil
|
|
---@return string Generated CSS
|
|
function M.generateComponentsCSS(dbal, tenantId, themeId)
|
|
local components = M.listComponents(dbal, tenantId, themeId)
|
|
local css = ''
|
|
|
|
for _, comp in ipairs(components) do
|
|
local styles = json.decode(comp.styles or '{}')
|
|
css = css .. comp.selector .. ' {\n'
|
|
for prop, value in pairs(styles) do
|
|
css = css .. ' ' .. prop .. ': ' .. value .. ';\n'
|
|
end
|
|
css = css .. '}\n\n'
|
|
|
|
-- Add variants if present
|
|
local variants = comp.variants and json.decode(comp.variants) or nil
|
|
if variants then
|
|
for variant, varStyles in pairs(variants) do
|
|
css = css .. comp.selector .. ':' .. variant .. ' {\n'
|
|
for prop, value in pairs(varStyles) do
|
|
css = css .. ' ' .. prop .. ': ' .. value .. ';\n'
|
|
end
|
|
css = css .. '}\n\n'
|
|
end
|
|
end
|
|
end
|
|
|
|
return css
|
|
end
|
|
|
|
---Generate complete CSS bundle
|
|
---@param dbal table
|
|
---@param tenantId string
|
|
---@param themeId string
|
|
---@return string Complete CSS
|
|
function M.generateFullCSS(dbal, tenantId, themeId)
|
|
local css = '/* Generated Theme CSS */\n\n'
|
|
css = css .. M.generateVariablesCSS(dbal, themeId)
|
|
css = css .. '\n/* Component Styles */\n\n'
|
|
css = css .. M.generateComponentsCSS(dbal, tenantId, themeId)
|
|
return css
|
|
end
|
|
|
|
---------------------------------------------------------------------------
|
|
-- PRESET MANAGEMENT
|
|
---------------------------------------------------------------------------
|
|
|
|
---Save theme as preset
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@param presetName string
|
|
---@param description string|nil
|
|
function M.saveAsPreset(dbal, themeId, presetName, description)
|
|
local theme = M.getTheme(dbal, themeId)
|
|
if not theme then
|
|
error('Theme not found: ' .. themeId)
|
|
end
|
|
|
|
return dbal:create('ThemePreset', {
|
|
tenantId = theme.tenantId,
|
|
name = presetName,
|
|
description = description,
|
|
variables = json.encode(theme.variables),
|
|
baseTheme = theme.baseTheme,
|
|
createdAt = os.time() * 1000,
|
|
})
|
|
end
|
|
|
|
---List available presets
|
|
---@param dbal table
|
|
---@param tenantId string
|
|
---@return table[] Presets
|
|
function M.listPresets(dbal, tenantId)
|
|
local result = dbal:list('ThemePreset', {
|
|
where = { tenantId = tenantId },
|
|
orderBy = { name = 'asc' },
|
|
take = 50,
|
|
})
|
|
return result.items or {}
|
|
end
|
|
|
|
---Apply preset to theme
|
|
---@param dbal table
|
|
---@param themeId string
|
|
---@param presetId string
|
|
function M.applyPreset(dbal, themeId, presetId)
|
|
local preset = dbal:read('ThemePreset', presetId)
|
|
if not preset then
|
|
error('Preset not found: ' .. presetId)
|
|
end
|
|
|
|
local variables = json.decode(preset.variables or '{}')
|
|
return M.updateTheme(dbal, themeId, {
|
|
variables = variables,
|
|
baseTheme = preset.baseTheme,
|
|
})
|
|
end
|
|
|
|
return M
|