mirror of
https://github.com/seemueller-io/yachtpit.git
synced 2025-09-08 22:46:45 +00:00
Modularize (#1)
* configure workspaces * Modularize domain logic by creating a new `models` crate. * Moved `LoadingPlugin` and `MenuPlugin` from `core` to a new `ui` module. Updated imports accordingly. * add theme for instruments * trunk serve works, remove audio and textures * remove loading indicator and assets * rename models to systems * seperate systems and components from models * Refactor instrument cluster to leverage reusable composition utilities. --------- Co-authored-by: geoffsee <>
This commit is contained in:
17
crates/components/Cargo.toml
Normal file
17
crates/components/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "components"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
bevy = { workspace = true, features = [
|
||||
"bevy_asset",
|
||||
"bevy_color",
|
||||
"bevy_core_pipeline",
|
||||
"bevy_render",
|
||||
"bevy_sprite",
|
||||
"bevy_text",
|
||||
"bevy_ui",
|
||||
"bevy_window",
|
||||
] }
|
228
crates/components/src/cluster.rs
Normal file
228
crates/components/src/cluster.rs
Normal file
@@ -0,0 +1,228 @@
|
||||
use bevy::prelude::*;
|
||||
use super::instruments::*;
|
||||
use super::theme::*;
|
||||
use super::composition::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct InstrumentCluster;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct GpsIndicator;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct RadarIndicator;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct AisIndicator;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct SystemDisplay;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct WindDisplay;
|
||||
|
||||
/// Sets up the main instrument cluster UI using composable components
|
||||
pub fn setup_instrument_cluster(mut commands: Commands) {
|
||||
// Spawn camera since we're bypassing the menu system
|
||||
commands.spawn((Camera2d, Msaa::Off));
|
||||
|
||||
// Create main container using composition
|
||||
commands.spawn((
|
||||
main_container_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
InstrumentCluster,
|
||||
))
|
||||
.with_children(|parent| {
|
||||
// Top row - Main navigation and speed (60% height)
|
||||
parent.spawn(row_container_node(60.0, 20.0))
|
||||
.with_children(|row| {
|
||||
// Speed Gauge
|
||||
row.spawn((
|
||||
circular_gauge_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
SpeedGauge,
|
||||
))
|
||||
.with_children(|gauge| {
|
||||
gauge.spawn(create_text("SPEED", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
gauge.spawn(create_text("12.5", FONT_SIZE_LARGE, TEXT_COLOR_SUCCESS));
|
||||
gauge.spawn(create_text("KTS", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// Central Navigation Display
|
||||
row.spawn((
|
||||
navigation_display_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_ACCENT),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
NavigationDisplay,
|
||||
))
|
||||
.with_children(|nav| {
|
||||
nav.spawn(create_text("NAVIGATION", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
nav.spawn((
|
||||
create_text("045°", FONT_SIZE_LARGE, TEXT_COLOR_PRIMARY).0,
|
||||
create_text("045°", FONT_SIZE_LARGE, TEXT_COLOR_PRIMARY).1,
|
||||
create_text("045°", FONT_SIZE_LARGE, TEXT_COLOR_PRIMARY).2,
|
||||
CompassGauge,
|
||||
));
|
||||
nav.spawn(create_text("HEADING", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// Depth Gauge
|
||||
row.spawn((
|
||||
circular_gauge_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
DepthGauge,
|
||||
))
|
||||
.with_children(|gauge| {
|
||||
gauge.spawn(create_text("DEPTH", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
gauge.spawn(create_text("15.2", FONT_SIZE_LARGE, Color::linear_rgb(0.0, 1.0, 0.8)));
|
||||
gauge.spawn(create_text("M", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
});
|
||||
|
||||
// Bottom row - Engine and system status (40% height)
|
||||
parent.spawn(row_container_node(40.0, 20.0))
|
||||
.with_children(|row| {
|
||||
// Engine Status Panel
|
||||
row.spawn((
|
||||
status_panel_node(200.0, 150.0),
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
EngineStatus,
|
||||
))
|
||||
.with_children(|panel| {
|
||||
panel.spawn(create_text("ENGINE", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
panel.spawn(create_text("82°C", FONT_SIZE_LARGE, TEXT_COLOR_SUCCESS));
|
||||
panel.spawn(create_text("TEMP NORMAL", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// System Status Grid
|
||||
row.spawn((
|
||||
status_panel_node(250.0, 150.0),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
BorderColor(BORDER_COLOR_SECONDARY),
|
||||
))
|
||||
.with_children(|grid| {
|
||||
grid.spawn(create_text("SYSTEMS", 12.0, TEXT_COLOR_SECONDARY));
|
||||
|
||||
// Fuel Level Bar
|
||||
grid.spawn(progress_bar_node())
|
||||
.with_children(|bar| {
|
||||
bar.spawn(create_text("FUEL", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
bar.spawn((
|
||||
progress_bar_background_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
BorderColor(TEXT_COLOR_PRIMARY),
|
||||
))
|
||||
.with_children(|bar_bg| {
|
||||
bar_bg.spawn((
|
||||
progress_bar_fill_node(75.0),
|
||||
BackgroundColor(TEXT_COLOR_SUCCESS),
|
||||
));
|
||||
});
|
||||
bar.spawn(create_text("75%", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// Battery Level Bar
|
||||
grid.spawn(progress_bar_node())
|
||||
.with_children(|bar| {
|
||||
bar.spawn(create_text("BATTERY", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
bar.spawn((
|
||||
progress_bar_background_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
BorderColor(BORDER_COLOR_SECONDARY),
|
||||
))
|
||||
.with_children(|bar_bg| {
|
||||
bar_bg.spawn((
|
||||
progress_bar_fill_node(88.0),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
));
|
||||
});
|
||||
bar.spawn(create_text("88%", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// System Status Indicators
|
||||
grid.spawn(Node {
|
||||
flex_direction: FlexDirection::Row,
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
width: Val::Percent(100.0),
|
||||
..default()
|
||||
})
|
||||
.with_children(|indicators| {
|
||||
// GPS Indicator
|
||||
indicators.spawn((
|
||||
Button,
|
||||
system_indicator_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
BorderColor(BORDER_COLOR_SECONDARY),
|
||||
GpsIndicator,
|
||||
))
|
||||
.with_children(|indicator| {
|
||||
indicator.spawn(create_text("🛰️", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
indicator.spawn(create_text("GPS", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// RADAR Indicator
|
||||
indicators.spawn((
|
||||
Button,
|
||||
system_indicator_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
BorderColor(BORDER_COLOR_SECONDARY),
|
||||
RadarIndicator,
|
||||
))
|
||||
.with_children(|indicator| {
|
||||
indicator.spawn(create_text("📡", FONT_SIZE_NORMAL, Color::linear_rgb(0.0, 1.0, 0.0)));
|
||||
indicator.spawn(create_text("RADAR", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
|
||||
// AIS Indicator
|
||||
indicators.spawn((
|
||||
Button,
|
||||
system_indicator_node(),
|
||||
BackgroundColor(BACKGROUND_COLOR_SECONDARY),
|
||||
BorderColor(BORDER_COLOR_SECONDARY),
|
||||
AisIndicator,
|
||||
))
|
||||
.with_children(|indicator| {
|
||||
indicator.spawn(create_text("🚢", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
indicator.spawn(create_text("AIS", FONT_SIZE_SMALL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Wind Information
|
||||
row.spawn((
|
||||
status_panel_node(200.0, 150.0),
|
||||
BackgroundColor(BACKGROUND_COLOR_ACCENT),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
WindDisplay,
|
||||
))
|
||||
.with_children(|panel| {
|
||||
panel.spawn(create_text("WIND", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
panel.spawn(create_text("8.3 KTS", FONT_SIZE_NORMAL, TEXT_COLOR_SUCCESS));
|
||||
panel.spawn(create_text("120° REL", FONT_SIZE_NORMAL, TEXT_COLOR_PRIMARY));
|
||||
});
|
||||
});
|
||||
|
||||
// System Display Area
|
||||
parent.spawn((
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Px(200.0),
|
||||
border: UiRect::all(Val::Px(2.0)),
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(Val::Px(20.0)),
|
||||
..default()
|
||||
},
|
||||
BackgroundColor(BACKGROUND_COLOR_PRIMARY),
|
||||
BorderColor(BORDER_COLOR_PRIMARY),
|
||||
SystemDisplay,
|
||||
))
|
||||
.with_children(|display| {
|
||||
display.spawn(create_text("Select a system above to view details", FONT_SIZE_SMALL, TEXT_COLOR_SECONDARY));
|
||||
});
|
||||
});
|
||||
}
|
123
crates/components/src/composition.rs
Normal file
123
crates/components/src/composition.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
/// Composition utilities for building instrument cluster components
|
||||
/// This module provides reusable building blocks for creating UI components
|
||||
|
||||
/// Creates a circular gauge node bundle
|
||||
pub fn circular_gauge_node() -> Node {
|
||||
Node {
|
||||
width: Val::Px(180.0),
|
||||
height: Val::Px(180.0),
|
||||
border: UiRect::all(Val::Px(2.0)),
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a status panel node bundle
|
||||
pub fn status_panel_node(width: f32, height: f32) -> Node {
|
||||
Node {
|
||||
width: Val::Px(width),
|
||||
height: Val::Px(height),
|
||||
border: UiRect::all(Val::Px(1.0)),
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::SpaceEvenly,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(Val::Px(10.0)),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a progress bar container node
|
||||
pub fn progress_bar_node() -> Node {
|
||||
Node {
|
||||
flex_direction: FlexDirection::Row,
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::SpaceBetween,
|
||||
width: Val::Percent(100.0),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a progress bar background node
|
||||
pub fn progress_bar_background_node() -> Node {
|
||||
Node {
|
||||
width: Val::Px(80.0),
|
||||
height: Val::Px(8.0),
|
||||
border: UiRect::all(Val::Px(1.0)),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a progress bar fill node
|
||||
pub fn progress_bar_fill_node(percentage: f32) -> Node {
|
||||
Node {
|
||||
width: Val::Percent(percentage),
|
||||
height: Val::Percent(100.0),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a system indicator button node
|
||||
pub fn system_indicator_node() -> Node {
|
||||
Node {
|
||||
flex_direction: FlexDirection::Column,
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
padding: UiRect::all(Val::Px(8.0)),
|
||||
width: Val::Px(60.0),
|
||||
height: Val::Px(40.0),
|
||||
border: UiRect::all(Val::Px(1.0)),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a navigation display node
|
||||
pub fn navigation_display_node() -> Node {
|
||||
Node {
|
||||
width: Val::Px(300.0),
|
||||
height: Val::Px(300.0),
|
||||
border: UiRect::all(Val::Px(2.0)),
|
||||
flex_direction: FlexDirection::Column,
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a row container node
|
||||
pub fn row_container_node(height_percent: f32, padding: f32) -> Node {
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(height_percent),
|
||||
flex_direction: FlexDirection::Row,
|
||||
justify_content: JustifyContent::SpaceEvenly,
|
||||
align_items: AlignItems::Center,
|
||||
padding: UiRect::all(Val::Px(padding)),
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the main container node
|
||||
pub fn main_container_node() -> Node {
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(100.0),
|
||||
flex_direction: FlexDirection::Column,
|
||||
..default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a text bundle with specified content, font size, and color
|
||||
pub fn create_text(content: &str, font_size: f32, color: Color) -> (Text, TextFont, TextColor) {
|
||||
(
|
||||
Text::new(content),
|
||||
TextFont {
|
||||
font_size,
|
||||
..default()
|
||||
},
|
||||
TextColor(color),
|
||||
)
|
||||
}
|
106
crates/components/src/instruments.rs
Normal file
106
crates/components/src/instruments.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
/// Individual instrument components
|
||||
#[derive(Component)]
|
||||
pub struct SpeedGauge;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct DepthGauge;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CompassGauge;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct EngineStatus;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct NavigationDisplay;
|
||||
|
||||
/// Yacht data resource containing all sensor readings
|
||||
#[derive(Resource)]
|
||||
pub struct YachtData {
|
||||
pub speed: f32, // knots
|
||||
pub depth: f32, // meters
|
||||
pub heading: f32, // degrees
|
||||
pub engine_temp: f32, // celsius
|
||||
pub fuel_level: f32, // percentage
|
||||
pub battery_level: f32, // percentage
|
||||
pub wind_speed: f32, // knots
|
||||
pub wind_direction: f32, // degrees
|
||||
}
|
||||
|
||||
impl Default for YachtData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
speed: 12.5,
|
||||
depth: 15.2,
|
||||
heading: 045.0,
|
||||
engine_temp: 82.0,
|
||||
fuel_level: 75.0,
|
||||
battery_level: 88.0,
|
||||
wind_speed: 8.3,
|
||||
wind_direction: 120.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates yacht data with simulated sensor readings
|
||||
pub fn update_yacht_data(mut yacht_data: ResMut<YachtData>, time: Res<Time>) {
|
||||
let t = time.elapsed_secs();
|
||||
|
||||
// Simulate realistic yacht data with some variation
|
||||
yacht_data.speed = 12.5 + (t * 0.3).sin() * 2.0;
|
||||
yacht_data.depth = 15.2 + (t * 0.1).sin() * 3.0;
|
||||
yacht_data.heading = (yacht_data.heading + time.delta_secs() * 5.0) % 360.0;
|
||||
yacht_data.engine_temp = 82.0 + (t * 0.2).sin() * 3.0;
|
||||
yacht_data.wind_speed = 8.3 + (t * 0.4).sin() * 1.5;
|
||||
yacht_data.wind_direction = (yacht_data.wind_direction + time.delta_secs() * 10.0) % 360.0;
|
||||
|
||||
// Slowly drain fuel and battery (very slowly for demo purposes)
|
||||
yacht_data.fuel_level = (yacht_data.fuel_level - time.delta_secs() * 0.01).max(0.0);
|
||||
yacht_data.battery_level = (yacht_data.battery_level - time.delta_secs() * 0.005).max(0.0);
|
||||
}
|
||||
|
||||
/// Updates the display values for all instrument gauges
|
||||
pub fn update_instrument_displays(
|
||||
yacht_data: Res<YachtData>,
|
||||
mut speed_query: Query<&mut Text, (With<SpeedGauge>, Without<DepthGauge>, Without<CompassGauge>)>,
|
||||
mut depth_query: Query<&mut Text, (With<DepthGauge>, Without<SpeedGauge>, Without<CompassGauge>)>,
|
||||
mut compass_query: Query<&mut Text, (With<CompassGauge>, Without<SpeedGauge>, Without<DepthGauge>)>,
|
||||
) {
|
||||
// Update speed display
|
||||
for mut text in speed_query.iter_mut() {
|
||||
if text.0.contains('.') {
|
||||
text.0 = format!("{:.1}", yacht_data.speed);
|
||||
}
|
||||
}
|
||||
|
||||
// Update depth display
|
||||
for mut text in depth_query.iter_mut() {
|
||||
if text.0.contains('.') {
|
||||
text.0 = format!("{:.1}", yacht_data.depth);
|
||||
}
|
||||
}
|
||||
|
||||
// Update compass display
|
||||
for mut text in compass_query.iter_mut() {
|
||||
if text.0.contains('°') {
|
||||
text.0 = format!("{:03.0}°", yacht_data.heading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_yacht_data_default() {
|
||||
let yacht_data = YachtData::default();
|
||||
assert_eq!(yacht_data.speed, 12.5);
|
||||
assert_eq!(yacht_data.depth, 15.2);
|
||||
assert_eq!(yacht_data.heading, 45.0);
|
||||
assert_eq!(yacht_data.fuel_level, 75.0);
|
||||
assert_eq!(yacht_data.battery_level, 88.0);
|
||||
}
|
||||
}
|
16
crates/components/src/lib.rs
Normal file
16
crates/components/src/lib.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
#![allow(clippy::type_complexity)]
|
||||
|
||||
// Components crate for yacht pit application
|
||||
// This crate contains reusable UI and game components
|
||||
|
||||
pub mod ui;
|
||||
pub mod instruments;
|
||||
pub mod theme;
|
||||
pub mod cluster;
|
||||
pub mod composition;
|
||||
|
||||
pub use ui::*;
|
||||
pub use instruments::*;
|
||||
pub use theme::*;
|
||||
pub use cluster::*;
|
||||
pub use composition::*;
|
34
crates/components/src/theme.rs
Normal file
34
crates/components/src/theme.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::color::Color;
|
||||
|
||||
pub const BACKGROUND_COLOR_PRIMARY: Color = Color::linear_rgb(0.05, 0.05, 0.1);
|
||||
pub const BACKGROUND_COLOR_SECONDARY: Color = Color::linear_rgb(0.1, 0.1, 0.15);
|
||||
pub const BACKGROUND_COLOR_ACCENT: Color = Color::linear_rgb(0.1, 0.15, 0.2);
|
||||
|
||||
pub const BORDER_COLOR_PRIMARY: Color = Color::linear_rgb(0.0, 0.8, 1.0);
|
||||
pub const BORDER_COLOR_SECONDARY: Color = Color::linear_rgb(0.8, 0.4, 0.0);
|
||||
pub const BORDER_COLOR_TERTIARY: Color = Color::linear_rgb(0.4, 0.4, 0.6);
|
||||
|
||||
pub const TEXT_COLOR_PRIMARY: Color = Color::linear_rgb(0.0, 0.8, 1.0);
|
||||
pub const TEXT_COLOR_SECONDARY: Color = Color::linear_rgb(0.6, 0.6, 0.6);
|
||||
pub const TEXT_COLOR_SUCCESS: Color = Color::linear_rgb(0.0, 1.0, 0.0);
|
||||
pub const TEXT_COLOR_WARNING: Color = Color::linear_rgb(0.8, 0.4, 0.0);
|
||||
pub const TEXT_COLOR_DANGER: Color = Color::linear_rgb(0.8, 0.0, 0.0);
|
||||
|
||||
pub const FONT_SIZE_SMALL: f32 = 10.0;
|
||||
pub const FONT_SIZE_NORMAL: f32 = 14.0;
|
||||
pub const FONT_SIZE_LARGE: f32 = 32.0;
|
||||
|
||||
pub const PADDING_DEFAULT: f32 = 20.0;
|
||||
pub const BORDER_WIDTH_DEFAULT: f32 = 2.0;
|
||||
|
||||
pub fn create_node_style(width: Val, height: Val, direction: FlexDirection) -> Node {
|
||||
Node {
|
||||
width,
|
||||
height,
|
||||
flex_direction: direction,
|
||||
justify_content: JustifyContent::Center,
|
||||
align_items: AlignItems::Center,
|
||||
..default()
|
||||
}
|
||||
}
|
14
crates/components/src/ui.rs
Normal file
14
crates/components/src/ui.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
// UI components for the yacht pit application
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
// Placeholder for UI components
|
||||
// This module will contain reusable UI components for the yacht pit application
|
||||
|
||||
pub struct ComponentsPlugin;
|
||||
|
||||
impl Plugin for ComponentsPlugin {
|
||||
fn build(&self, _app: &mut App) {
|
||||
// Add systems and resources for components here
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user