Files
Code_of_Conquest/godot_client/scenes/components/README.md
2025-11-24 23:10:55 -06:00

336 lines
7.4 KiB
Markdown

# Reusable UI Components
This directory contains reusable UI components for Code of Conquest.
## Available Components
### CustomButton
**Script**: `scripts/components/custom_button.gd`
Enhanced button with multiple visual variants and features.
**Features**:
- Multiple variants (Primary, Secondary, Danger, Success, Ghost)
- Icon support (left or right position)
- Loading state
- Hover effects
- Themed styling
**Usage**:
```gdscript
var btn = CustomButton.new()
btn.text = "Login"
btn.set_variant(CustomButton.Variant.PRIMARY)
btn.button_clicked.connect(_on_login_clicked)
add_child(btn)
```
**Variants**:
- `PRIMARY` - Gold accent button for main actions
- `SECONDARY` - Standard button
- `DANGER` - Red button for destructive actions (delete, etc.)
- `SUCCESS` - Green button for positive actions
- `GHOST` - Transparent/subtle button
### Card
**Script**: `scripts/components/card.gd`
Container with optional header and footer, styled like the web UI cards.
**Features**:
- Optional header with text
- Body content area
- Optional footer with buttons
- Multiple style variants
- Automatic sizing
**Usage**:
```gdscript
var card = Card.new()
card.set_header("Character Details")
var content = Label.new()
content.text = "Character information goes here"
card.add_content(content)
card.set_footer_buttons(["Save", "Cancel"])
card.footer_button_pressed.connect(_on_card_button_pressed)
add_child(card)
```
**Style Variants**:
- `DEFAULT` - Standard card with subtle border
- `HIGHLIGHTED` - Gold border with shadow
- `SUBTLE` - Minimal border
### FormField
**Script**: `scripts/components/form_field.gd`
Form input field with label, validation, and error display.
**Features**:
- Label + input + error message
- Multiple input types (text, email, password, number, phone)
- Built-in validation
- Required field support
- Min/max length validation
- Error state styling
**Usage**:
```gdscript
var email_field = FormField.new()
email_field.set_label("Email")
email_field.set_placeholder("Enter your email")
email_field.input_type = FormField.InputType.EMAIL
email_field.required = true
email_field.value_changed.connect(_on_email_changed)
add_child(email_field)
# Later, validate
if email_field.validate():
var email = email_field.get_value()
# Process email
```
**Input Types**:
- `TEXT` - Plain text
- `EMAIL` - Email validation
- `PASSWORD` - Hidden password
- `NUMBER` - Numeric only
- `PHONE` - Phone number format
## Creating New Components
### 1. Create Script
Create a new GDScript file in `scripts/components/`:
```gdscript
extends Control # or appropriate base class
class_name MyComponent
## MyComponent
##
## Brief description of what this component does
##
## Usage:
## var comp = MyComponent.new()
## comp.some_property = "value"
signal some_signal(data: String)
@export var some_property: String = ""
func _ready() -> void:
_setup_structure()
_apply_styling()
func _setup_structure() -> void:
# Build node hierarchy
pass
func _apply_styling() -> void:
# Apply theme colors and styleboxes
pass
```
### 2. Use Theme Colors
Always use `ThemeColors` constants:
```gdscript
var style = StyleBoxFlat.new()
style.bg_color = ThemeColors.BACKGROUND_CARD
style.border_color = ThemeColors.BORDER_DEFAULT
```
### 3. Make It Configurable
Use `@export` variables for Godot Inspector:
```gdscript
@export var title: String = ""
@export_enum("Small", "Medium", "Large") var size: String = "Medium"
@export var show_icon: bool = true
```
### 4. Emit Signals
For user interactions:
```gdscript
signal item_selected(item_id: String)
signal value_changed(new_value: Variant)
func _on_internal_action():
item_selected.emit("some_id")
```
### 5. Document Usage
Include usage examples in docstring:
```gdscript
## MyComponent
##
## Detailed description of the component.
##
## Usage:
## var comp = MyComponent.new()
## comp.title = "My Title"
## comp.item_selected.connect(_on_item_selected)
## add_child(comp)
```
## Component Patterns
### Separation of Structure and Style
```gdscript
func _ready() -> void:
_setup_structure() # Build node hierarchy
_apply_styling() # Apply theme
func _setup_structure() -> void:
# Create child nodes
# Set up hierarchy
# Connect signals
pass
func _apply_styling() -> void:
# Apply StyleBoxes
# Set colors
# Set fonts
pass
```
### Responsive Design
```gdscript
func _apply_styling() -> void:
# Check platform
var is_mobile = OS.get_name() in ["Android", "iOS"]
if is_mobile:
# Larger touch targets
custom_minimum_size = Vector2(60, 60)
else:
# Desktop sizing
custom_minimum_size = Vector2(40, 40)
```
### Validation Pattern
```gdscript
func validate() -> bool:
var is_valid = true
# Check conditions
if some_condition:
show_error("Error message")
is_valid = false
if is_valid:
clear_error()
return is_valid
```
## Testing Components
Create a test scene `test_components.tscn`:
1. Add each component
2. Test all variants
3. Test all states (normal, hover, pressed, disabled)
4. Test on different screen sizes
5. Test on different platforms
Example test scene structure:
```
Control (root)
├─ VBoxContainer
│ ├─ Label ("Buttons")
│ ├─ HBoxContainer
│ │ ├─ CustomButton (Primary)
│ │ ├─ CustomButton (Secondary)
│ │ ├─ CustomButton (Danger)
│ │ └─ CustomButton (Ghost)
│ ├─ Label ("Cards")
│ ├─ HBoxContainer
│ │ ├─ Card (Default)
│ │ ├─ Card (Highlighted)
│ │ └─ Card (Subtle)
│ └─ Label ("Form Fields")
│ ├─ FormField (Text)
│ ├─ FormField (Email)
│ └─ FormField (Password)
```
## Best Practices
1. **Always use ThemeColors** - Never hardcode colors
2. **Make components reusable** - Avoid scene-specific logic
3. **Use signals for communication** - Don't couple components
4. **Document everything** - Docstrings + usage examples
5. **Test on all platforms** - Desktop, mobile, web
6. **Follow naming conventions** - PascalCase for class names
7. **Export important properties** - Make them editable in Inspector
8. **Validate inputs** - Check types and ranges
9. **Handle edge cases** - Empty strings, null values, etc.
10. **Keep it simple** - One component, one responsibility
## Common Pitfalls
### ❌ Don't hardcode colors
```gdscript
var style = StyleBoxFlat.new()
style.bg_color = Color("#1a1a2e") # BAD
```
### ✅ Use ThemeColors
```gdscript
var style = StyleBoxFlat.new()
style.bg_color = ThemeColors.BACKGROUND_PRIMARY # GOOD
```
### ❌ Don't create nodes in every frame
```gdscript
func _process(delta):
var button = Button.new() # BAD - leaks memory
add_child(button)
```
### ✅ Create once in _ready
```gdscript
var button: Button
func _ready():
button = Button.new()
add_child(button)
```
### ❌ Don't couple components
```gdscript
# In a button component
func _on_pressed():
get_parent().get_node("SomeOtherNode").do_something() # BAD
```
### ✅ Use signals
```gdscript
signal action_requested
func _on_pressed():
action_requested.emit() # GOOD
```
## Resources
- [Godot UI Documentation](https://docs.godotengine.org/en/stable/tutorials/ui/index.html)
- [Control Nodes](https://docs.godotengine.org/en/stable/classes/class_control.html)
- [Themes](https://docs.godotengine.org/en/stable/tutorials/ui/gui_using_theme_editor.html)
- [StyleBox](https://docs.godotengine.org/en/stable/classes/class_stylebox.html)