diff --git a/fakemui/index.ts b/fakemui/index.ts index e24148781..c3e576085 100644 --- a/fakemui/index.ts +++ b/fakemui/index.ts @@ -26,7 +26,7 @@ export { Settings, User, UserCheck, - Menu, + Menu as MenuIcon, Eye, EyeSlash, Pencil, diff --git a/packages/css_designer/seed/components.json b/packages/css_designer/seed/components.json new file mode 100644 index 000000000..23c5a2779 --- /dev/null +++ b/packages/css_designer/seed/components.json @@ -0,0 +1,242 @@ +{ + "components": [ + { + "id": "CSSDesigner", + "type": "layout", + "props": { + "title": "CSS Designer", + "layout": "sidebar" + }, + "children": [ + { "ref": "ColorPaletteEditor" }, + { "ref": "FontSelector" }, + { "ref": "SpacingEditor" }, + { "ref": "BorderEditor" }, + { "ref": "ShadowEditor" }, + { "ref": "StylePreview" } + ], + "scripts": { + "onInit": "init.lua", + "onSave": "export/to_scss.lua" + } + }, + { + "id": "ColorPaletteEditor", + "type": "form", + "props": { + "title": "Color Palette", + "icon": "Palette" + }, + "children": [ + { + "type": "color_picker", + "props": { "id": "primary", "label": "Primary Color", "defaultValue": "#1976d2" } + }, + { + "type": "color_picker", + "props": { "id": "secondary", "label": "Secondary Color", "defaultValue": "#9c27b0" } + }, + { + "type": "color_picker", + "props": { "id": "background", "label": "Background", "defaultValue": "#ffffff" } + }, + { + "type": "color_picker", + "props": { "id": "surface", "label": "Surface", "defaultValue": "#f5f5f5" } + }, + { + "type": "color_picker", + "props": { "id": "text_primary", "label": "Text Primary", "defaultValue": "#212121" } + }, + { + "type": "color_picker", + "props": { "id": "text_secondary", "label": "Text Secondary", "defaultValue": "#757575" } + }, + { + "type": "color_picker", + "props": { "id": "error", "label": "Error", "defaultValue": "#f44336" } + }, + { + "type": "color_picker", + "props": { "id": "warning", "label": "Warning", "defaultValue": "#ff9800" } + }, + { + "type": "color_picker", + "props": { "id": "success", "label": "Success", "defaultValue": "#4caf50" } + }, + { + "type": "color_picker", + "props": { "id": "info", "label": "Info", "defaultValue": "#2196f3" } + } + ], + "scripts": { + "onColorChange": "colors/color_picker.lua" + } + }, + { + "id": "FontSelector", + "type": "form", + "props": { + "title": "Typography", + "icon": "TextFields" + }, + "children": [ + { + "type": "select", + "props": { + "id": "fontFamily", + "label": "Font Family", + "options": [ + { "value": "IBM Plex Sans", "label": "IBM Plex Sans (Default)" }, + { "value": "Inter", "label": "Inter" }, + { "value": "Roboto", "label": "Roboto" }, + { "value": "Open Sans", "label": "Open Sans" }, + { "value": "system-ui", "label": "System UI" } + ] + } + }, + { + "type": "select", + "props": { + "id": "headingFont", + "label": "Heading Font", + "options": [ + { "value": "Space Grotesk", "label": "Space Grotesk (Default)" }, + { "value": "Poppins", "label": "Poppins" }, + { "value": "Montserrat", "label": "Montserrat" } + ] + } + }, + { + "type": "select", + "props": { + "id": "codeFont", + "label": "Code Font", + "options": [ + { "value": "JetBrains Mono", "label": "JetBrains Mono (Default)" }, + { "value": "Fira Code", "label": "Fira Code" }, + { "value": "Source Code Pro", "label": "Source Code Pro" } + ] + } + }, + { + "type": "slider", + "props": { + "id": "baseFontSize", + "label": "Base Font Size", + "min": 12, + "max": 20, + "defaultValue": 16, + "unit": "px" + } + } + ], + "scripts": { + "onFontChange": "fonts/font_selector.lua" + } + }, + { + "id": "SpacingEditor", + "type": "form", + "props": { + "title": "Spacing", + "icon": "Grid" + }, + "children": [ + { + "type": "slider", + "props": { "id": "spacingUnit", "label": "Base Unit", "min": 4, "max": 16, "defaultValue": 8, "unit": "px" } + }, + { + "type": "slider", + "props": { "id": "borderRadius", "label": "Border Radius", "min": 0, "max": 24, "defaultValue": 4, "unit": "px" } + }, + { + "type": "slider", + "props": { "id": "containerWidth", "label": "Container Width", "min": 900, "max": 1400, "defaultValue": 1200, "unit": "px" } + } + ], + "scripts": { + "onSpacingChange": "spacing/spacing_editor.lua" + } + }, + { + "id": "BorderEditor", + "type": "form", + "props": { + "title": "Borders", + "icon": "CropFree" + }, + "children": [ + { + "type": "slider", + "props": { "id": "borderWidth", "label": "Border Width", "min": 0, "max": 4, "defaultValue": 1, "unit": "px" } + }, + { + "type": "color_picker", + "props": { "id": "borderColor", "label": "Border Color", "defaultValue": "#e0e0e0" } + }, + { + "type": "select", + "props": { + "id": "borderStyle", + "label": "Border Style", + "options": [ + { "value": "solid", "label": "Solid" }, + { "value": "dashed", "label": "Dashed" }, + { "value": "dotted", "label": "Dotted" } + ] + } + } + ], + "scripts": { + "onBorderChange": "borders/border_editor.lua" + } + }, + { + "id": "ShadowEditor", + "type": "form", + "props": { + "title": "Shadows", + "icon": "Layers" + }, + "children": [ + { + "type": "slider", + "props": { "id": "shadowBlur", "label": "Blur Radius", "min": 0, "max": 24, "defaultValue": 4, "unit": "px" } + }, + { + "type": "slider", + "props": { "id": "shadowSpread", "label": "Spread", "min": 0, "max": 12, "defaultValue": 0, "unit": "px" } + }, + { + "type": "slider", + "props": { "id": "shadowOpacity", "label": "Opacity", "min": 0, "max": 100, "defaultValue": 15, "unit": "%" } + } + ], + "scripts": { + "onShadowChange": "shadows/shadow_editor.lua" + } + }, + { + "id": "StylePreview", + "type": "preview", + "props": { + "title": "Preview", + "icon": "Eye" + }, + "children": [ + { + "type": "card", + "props": { "className": "preview-card" }, + "children": [ + { "type": "typography", "props": { "variant": "h4", "text": "Heading Preview" } }, + { "type": "typography", "props": { "variant": "body1", "text": "This is body text to preview your typography settings." } }, + { "type": "button", "props": { "variant": "contained", "text": "Primary Button" } }, + { "type": "button", "props": { "variant": "outlined", "text": "Secondary Button" } } + ] + } + ] + } + ] +} diff --git a/packages/css_designer/seed/scripts/colors/color_picker.lua b/packages/css_designer/seed/scripts/colors/color_picker.lua new file mode 100644 index 000000000..5f5aaf908 --- /dev/null +++ b/packages/css_designer/seed/scripts/colors/color_picker.lua @@ -0,0 +1,134 @@ +-- Color picker utility functions +-- Single-purpose module for color conversion and manipulation + +---@class ColorPicker +local M = {} + +---Convert hex color to RGB +---@param hex string Hex color (e.g., "#1976d2" or "1976d2") +---@return RGBColor|nil rgb RGB color or nil if invalid +function M.hex_to_rgb(hex) + if not hex then return nil end + + -- Remove # prefix if present + hex = hex:gsub("^#", "") + + -- Validate length + if #hex ~= 6 and #hex ~= 3 then + return nil + end + + -- Expand shorthand (e.g., "abc" -> "aabbcc") + if #hex == 3 then + hex = hex:sub(1,1):rep(2) .. hex:sub(2,2):rep(2) .. hex:sub(3,3):rep(2) + end + + local r = tonumber(hex:sub(1,2), 16) + local g = tonumber(hex:sub(3,4), 16) + local b = tonumber(hex:sub(5,6), 16) + + if not r or not g or not b then + return nil + end + + return { r = r, g = g, b = b } +end + +---Convert RGB to hex color +---@param rgb RGBColor RGB color +---@return string hex Hex color string +function M.rgb_to_hex(rgb) + return string.format("#%02x%02x%02x", rgb.r, rgb.g, rgb.b) +end + +---Convert hex to HSL color +---@param hex string Hex color +---@return HSLColor|nil hsl HSL color or nil if invalid +function M.hex_to_hsl(hex) + local rgb = M.hex_to_rgb(hex) + if not rgb then return nil end + + local r, g, b = rgb.r / 255, rgb.g / 255, rgb.b / 255 + local max, min = math.max(r, g, b), math.min(r, g, b) + local h, s, l = 0, 0, (max + min) / 2 + + if max ~= min then + local d = max - min + s = l > 0.5 and d / (2 - max - min) or d / (max + min) + + if max == r then + h = (g - b) / d + (g < b and 6 or 0) + elseif max == g then + h = (b - r) / d + 2 + else + h = (r - g) / d + 4 + end + + h = h / 6 + end + + return { + h = math.floor(h * 360), + s = math.floor(s * 100), + l = math.floor(l * 100) + } +end + +---Convert HSL to hex color +---@param hsl HSLColor HSL color +---@return string hex Hex color string +function M.hsl_to_hex(hsl) + local h, s, l = hsl.h / 360, hsl.s / 100, hsl.l / 100 + + local function hue_to_rgb(p, q, t) + if t < 0 then t = t + 1 end + if t > 1 then t = t - 1 end + if t < 1/6 then return p + (q - p) * 6 * t end + if t < 1/2 then return q end + if t < 2/3 then return p + (q - p) * (2/3 - t) * 6 end + return p + end + + local r, g, b + if s == 0 then + r, g, b = l, l, l + else + local q = l < 0.5 and l * (1 + s) or l + s - l * s + local p = 2 * l - q + r = hue_to_rgb(p, q, h + 1/3) + g = hue_to_rgb(p, q, h) + b = hue_to_rgb(p, q, h - 1/3) + end + + return M.rgb_to_hex({ + r = math.floor(r * 255 + 0.5), + g = math.floor(g * 255 + 0.5), + b = math.floor(b * 255 + 0.5) + }) +end + +---Adjust the lightness of a color +---@param hex string Hex color +---@param amount number Amount to adjust (-100 to 100) +---@return string hex Adjusted hex color +function M.adjust_lightness(hex, amount) + local hsl = M.hex_to_hsl(hex) + if not hsl then return hex end + + hsl.l = math.max(0, math.min(100, hsl.l + amount)) + return M.hsl_to_hex(hsl) +end + +---Adjust the saturation of a color +---@param hex string Hex color +---@param amount number Amount to adjust (-100 to 100) +---@return string hex Adjusted hex color +function M.adjust_saturation(hex, amount) + local hsl = M.hex_to_hsl(hex) + if not hsl then return hex end + + hsl.s = math.max(0, math.min(100, hsl.s + amount)) + return M.hsl_to_hex(hsl) +end + +return M diff --git a/packages/css_designer/seed/scripts/colors/init.lua b/packages/css_designer/seed/scripts/colors/init.lua new file mode 100644 index 000000000..952baa222 --- /dev/null +++ b/packages/css_designer/seed/scripts/colors/init.lua @@ -0,0 +1,23 @@ +-- Color utility functions facade +-- Re-exports all color-related functions + +local colorPicker = require("colors.color_picker") +local palette = require("colors.palette") + +---@class ColorsModule +local M = {} + +-- Re-export color picker functions +M.hex_to_rgb = colorPicker.hex_to_rgb +M.rgb_to_hex = colorPicker.rgb_to_hex +M.hex_to_hsl = colorPicker.hex_to_hsl +M.hsl_to_hex = colorPicker.hsl_to_hex +M.adjust_lightness = colorPicker.adjust_lightness +M.adjust_saturation = colorPicker.adjust_saturation + +-- Re-export palette functions +M.generate_shades = palette.generate_shades +M.generate_tints = palette.generate_tints +M.create_palette = palette.create_palette + +return M diff --git a/packages/css_designer/seed/scripts/colors/palette.lua b/packages/css_designer/seed/scripts/colors/palette.lua new file mode 100644 index 000000000..e06754e98 --- /dev/null +++ b/packages/css_designer/seed/scripts/colors/palette.lua @@ -0,0 +1,73 @@ +-- Color palette generation functions +-- Creates color variations from a base color + +local colorPicker = require("colors.color_picker") + +---@class Palette +local M = {} + +---Generate darker shades of a color +---@param hex string Base hex color +---@param count? number Number of shades (default 5) +---@return string[] shades Array of hex colors from base to darkest +function M.generate_shades(hex, count) + count = count or 5 + local shades = { hex } + local step = 80 / count + + for i = 1, count - 1 do + local shade = colorPicker.adjust_lightness(hex, -step * i) + table.insert(shades, shade) + end + + return shades +end + +---Generate lighter tints of a color +---@param hex string Base hex color +---@param count? number Number of tints (default 5) +---@return string[] tints Array of hex colors from base to lightest +function M.generate_tints(hex, count) + count = count or 5 + local tints = { hex } + local step = 80 / count + + for i = 1, count - 1 do + local tint = colorPicker.adjust_lightness(hex, step * i) + table.insert(tints, tint) + end + + return tints +end + +---Create a full color palette from a base color +---@param hex string Base hex color +---@return table palette Palette with shades and tints +function M.create_palette(hex) + local hsl = colorPicker.hex_to_hsl(hex) + if not hsl then + return { base = hex, shades = {hex}, tints = {hex} } + end + + -- Generate palette scales (50, 100, 200, ... 900) + local scale = {} + local lightness_values = {95, 90, 80, 70, 60, 50, 40, 30, 20, 10} + local scale_names = {50, 100, 200, 300, 400, 500, 600, 700, 800, 900} + + for i, l in ipairs(lightness_values) do + scale[scale_names[i]] = colorPicker.hsl_to_hex({ + h = hsl.h, + s = hsl.s, + l = l + }) + end + + return { + base = hex, + scale = scale, + shades = M.generate_shades(hex, 5), + tints = M.generate_tints(hex, 5) + } +end + +return M diff --git a/packages/css_designer/seed/scripts/init.lua b/packages/css_designer/seed/scripts/init.lua new file mode 100644 index 000000000..0b25de4c9 --- /dev/null +++ b/packages/css_designer/seed/scripts/init.lua @@ -0,0 +1,68 @@ +-- CSS Designer initialization +-- Main entry point for the css_designer package + +---@class CSSDesigner +---@field name string Package name +---@field version string Package version +local M = {} + +M.name = "css_designer" +M.version = "1.0.0" + +---@class InitResult +---@field name string Package name +---@field version string Package version +---@field loaded boolean Whether successfully loaded + +---Initialize the CSS designer module +---@return InitResult +function M.init() + return { + name = M.name, + version = M.version, + loaded = true + } +end + +---Get default theme configuration +---@return ThemeConfig +function M.get_default_theme() + return { + name = "Default", + colors = { + primary = { hex = "#1976d2" }, + secondary = { hex = "#9c27b0" }, + background = { hex = "#ffffff" }, + surface = { hex = "#f5f5f5" }, + text_primary = { hex = "#212121" }, + text_secondary = { hex = "#757575" }, + error = { hex = "#f44336" }, + warning = { hex = "#ff9800" }, + success = { hex = "#4caf50" }, + info = { hex = "#2196f3" } + }, + typography = { + fontFamily = "IBM Plex Sans", + headingFont = "Space Grotesk", + codeFont = "JetBrains Mono", + baseFontSize = 16 + }, + spacing = { + spacingUnit = 8, + borderRadius = 4, + containerWidth = 1200 + }, + borders = { + width = 1, + color = { hex = "#e0e0e0" }, + style = "solid" + }, + shadows = { + blur = 4, + spread = 0, + opacity = 15 + } + } +end + +return M diff --git a/packages/css_designer/seed/scripts/types.lua b/packages/css_designer/seed/scripts/types.lua new file mode 100644 index 000000000..d1d6f722f --- /dev/null +++ b/packages/css_designer/seed/scripts/types.lua @@ -0,0 +1,129 @@ +-- LuaCATS type definitions for css_designer package +-- Provides types for visual CSS design and style export +-- See: https://luals.github.io/wiki/annotations/ + +-------------------------------------------------------------------------------- +-- Color Types +-------------------------------------------------------------------------------- + +---@class ColorValue +---@field hex string Hex color value (e.g., "#1976d2") +---@field rgb? RGBColor RGB representation +---@field hsl? HSLColor HSL representation +---@field alpha? number Alpha/opacity (0-1) + +---@class RGBColor +---@field r number Red (0-255) +---@field g number Green (0-255) +---@field b number Blue (0-255) + +---@class HSLColor +---@field h number Hue (0-360) +---@field s number Saturation (0-100) +---@field l number Lightness (0-100) + +---@class ColorPalette +---@field primary ColorValue Primary brand color +---@field secondary ColorValue Secondary brand color +---@field background ColorValue Background color +---@field surface ColorValue Surface/card color +---@field text_primary ColorValue Primary text color +---@field text_secondary ColorValue Secondary text color +---@field error ColorValue Error state color +---@field warning ColorValue Warning state color +---@field success ColorValue Success state color +---@field info ColorValue Info state color + +-------------------------------------------------------------------------------- +-- Typography Types +-------------------------------------------------------------------------------- + +---@class TypographyConfig +---@field fontFamily string Primary font family +---@field headingFont string Heading font family +---@field codeFont string Monospace/code font family +---@field baseFontSize number Base font size in pixels +---@field lineHeight? number Line height multiplier +---@field letterSpacing? number Letter spacing in em + +---@class FontOption +---@field value string Font family value +---@field label string Display label +---@field category? "sans-serif"|"serif"|"monospace" Font category + +-------------------------------------------------------------------------------- +-- Spacing Types +-------------------------------------------------------------------------------- + +---@class SpacingConfig +---@field spacingUnit number Base spacing unit in pixels +---@field borderRadius number Default border radius in pixels +---@field containerWidth number Max container width in pixels + +---@class SpacingScale +---@field xs number Extra small spacing +---@field sm number Small spacing +---@field md number Medium spacing +---@field lg number Large spacing +---@field xl number Extra large spacing + +-------------------------------------------------------------------------------- +-- Border Types +-------------------------------------------------------------------------------- + +---@class BorderConfig +---@field width number Border width in pixels +---@field color ColorValue Border color +---@field style "solid"|"dashed"|"dotted"|"none" Border style +---@field radius? number Border radius override + +-------------------------------------------------------------------------------- +-- Shadow Types +-------------------------------------------------------------------------------- + +---@class ShadowConfig +---@field blur number Blur radius in pixels +---@field spread number Spread radius in pixels +---@field opacity number Shadow opacity (0-100) +---@field offsetX? number Horizontal offset +---@field offsetY? number Vertical offset +---@field color? ColorValue Shadow color + +---@class ShadowPreset +---@field name string Preset name +---@field config ShadowConfig Shadow configuration + +-------------------------------------------------------------------------------- +-- Theme Types +-------------------------------------------------------------------------------- + +---@class ThemeConfig +---@field name string Theme name +---@field colors ColorPalette Color palette +---@field typography TypographyConfig Typography settings +---@field spacing SpacingConfig Spacing settings +---@field borders BorderConfig Border defaults +---@field shadows ShadowConfig Shadow defaults + +---@class ThemeExport +---@field scss string SCSS variable output +---@field css string CSS custom properties output +---@field json string JSON configuration output + +-------------------------------------------------------------------------------- +-- Component Types +-------------------------------------------------------------------------------- + +---@class DesignerState +---@field theme ThemeConfig Current theme configuration +---@field isDirty boolean Has unsaved changes +---@field previewMode "light"|"dark" Preview mode + +---@class EditorProps +---@field value any Current value +---@field onChange fun(value: any): void Change handler +---@field label string Field label +---@field disabled? boolean Whether editor is disabled + +-- Export types (no runtime exports) +return {}