Skip to content

Commit 264cbbf

Browse files
Merge pull request #1 from KrLiam/features
Add global variable injection, marker components and named output slots
2 parents 9887946 + 10a237e commit 264cbbf

24 files changed

+889
-329
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ name = "neko-maid"
33
version = "0.1.0"
44
edition = "2024"
55

6+
[workspace]
7+
members = ["neko_derive"]
8+
69
[dependencies]
10+
neko_derive = { path="./neko_derive" }
711
bevy = { version = "0.17", default-features = false, features = [
812
"bevy_core_pipeline",
913
"bevy_render",

assets/example.neko_ui

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
// global variables that are controlled dynamically.
2+
var width = 400;
3+
var color = #000000;
4+
15
var text-color = #614a31;
26

37
style div +outer-menu {
@@ -16,7 +20,7 @@ style div +inner-menu {
1620

1721
style p +h1 {
1822
font-size: 32;
19-
color: $text-color;
23+
color: $color;
2024
}
2125

2226
def h1 {
@@ -48,7 +52,7 @@ layout div {
4852
flex-direction: column;
4953
align-items: center;
5054

51-
width: 400px;
55+
width: $width;
5256
height: 600px;
5357

5458
margin: auto;

assets/marker.neko_ui

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
2+
style div +outer-menu {
3+
background-color: #D5A96E;
4+
border-color: #5B4A31;
5+
border-thickness: 4px;
6+
border-radius: 12px;
7+
}
8+
9+
style div +inner-menu {
10+
background-color: #d9ad72;
11+
border-color: #c1935b;
12+
border-thickness: 4px;
13+
border-radius: 12px;
14+
}
15+
16+
style p +h1 {
17+
font-size: 32;
18+
color: #000000;
19+
}
20+
21+
def h1 {
22+
var text = "Text";
23+
24+
layout div {
25+
class test;
26+
27+
flex-direction: column;
28+
29+
with p {
30+
class h1;
31+
text: $text;
32+
}
33+
34+
with div {
35+
height: 2px;
36+
width: 100%;
37+
38+
background-color: #614a31;
39+
border-radius: 4px;
40+
}
41+
42+
output;
43+
}
44+
}
45+
46+
layout div {
47+
class outer-menu;
48+
49+
flex-direction: column;
50+
align-items: center;
51+
52+
width: 500px;
53+
height: 600px;
54+
55+
margin: auto;
56+
padding: 8px;
57+
row-gap: 8px;
58+
59+
with h1 {
60+
text: "Outer Menu";
61+
}
62+
63+
with div {
64+
class inner-menu;
65+
66+
width: 100%;
67+
flex-grow: 1;
68+
69+
padding: 8px;
70+
71+
with p {
72+
text: "Hiii";
73+
color: #000000;
74+
}
75+
76+
with div {
77+
class test;
78+
79+
width: 100px;
80+
height: 100px;
81+
}
82+
}
83+
}

assets/slots.neko_ui

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
2+
style p {
3+
color: #000;
4+
}
5+
6+
def centered {
7+
layout div {
8+
width: 100%;
9+
height: 100%;
10+
justify-content: center;
11+
align-items: center;
12+
13+
// same as output default;
14+
output;
15+
}
16+
}
17+
18+
def card {
19+
layout centered {
20+
// when 'in' is not used, child elements go
21+
// to the default slot.
22+
with div {
23+
flex-direction: column;
24+
width: 300px;
25+
height: 400px;
26+
background-color: #eeeeee;
27+
border-radius: 5px;
28+
29+
with div {
30+
width: 100%;
31+
height: 50px;
32+
border-color: #ccc;
33+
border-thickness-bottom: 2px;
34+
padding: 10px;
35+
36+
output header;
37+
}
38+
39+
with div {
40+
width: 100%;
41+
height: 100%;
42+
padding: 10px;
43+
44+
with div {
45+
width: 100%;
46+
height: 100%;
47+
border-color: #ccc;
48+
border-thickness: 2px;
49+
border-radius: 5px;
50+
51+
with p {
52+
text: "[";
53+
color: #aaa;
54+
}
55+
56+
output body;
57+
58+
with p {
59+
text: "]";
60+
color: #aaa;
61+
}
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
69+
layout div {
70+
width: 100%;
71+
justify-content: start;
72+
align-items: start;
73+
74+
with card {
75+
in header {
76+
with div {
77+
width: 100%;
78+
justify-content: center;
79+
background-color: #ccc;
80+
padding: 2px;
81+
border-radius: 5px;
82+
83+
with p {
84+
text: "Card Demo";
85+
}
86+
}
87+
}
88+
89+
in body {
90+
with p {
91+
text: "Body content.";
92+
}
93+
94+
// this raises an error since top-level layouts
95+
// cannot have output slots
96+
// output;
97+
}
98+
}
99+
100+
}

examples/marker.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use bevy::color::palettes::css::RED;
2+
use bevy::prelude::*;
3+
use neko_derive::NekoMarker;
4+
use neko_maid::components::NekoUITree;
5+
use neko_maid::marker::{MarkerAppExt, NekoMarker};
6+
7+
#[derive(Component, NekoMarker)]
8+
#[neko_marker("test")]
9+
pub struct Test;
10+
11+
fn main() {
12+
App::new()
13+
.add_plugins(DefaultPlugins)
14+
.add_plugins(neko_maid::NekoMaidPlugin)
15+
.add_marker::<Test>()
16+
.add_systems(Startup, setup)
17+
.add_observer(spawned_test)
18+
.run();
19+
}
20+
21+
fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
22+
commands.spawn(Camera2d);
23+
24+
let handle = asset_server.load("marker.neko_ui");
25+
commands.spawn(NekoUITree::new(handle));
26+
}
27+
28+
pub fn spawned_test(event: On<Add, Test>, mut cmds: Commands) {
29+
// Could add any arbitrary logic here. We're gonna just build some UI manually.
30+
31+
println!("Spawned test {}", event.entity);
32+
cmds.entity(event.entity).with_children(|parent| {
33+
parent.spawn((
34+
Node {
35+
position_type: PositionType::Absolute,
36+
left: Val::Px(0.0),
37+
top: Val::Px(0.0),
38+
bottom: Val::Px(0.0),
39+
right: Val::Px(0.0),
40+
width: Val::Auto,
41+
height: Val::Auto,
42+
border: UiRect::all(Val::Px(2.0)),
43+
..Default::default()
44+
},
45+
BorderColor::all(RED),
46+
BackgroundColor(Color::NONE),
47+
));
48+
});
49+
}

examples/menu.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use bevy::prelude::*;
22
use neko_maid::components::NekoUITree;
3+
use neko_maid::parse::value::PropertyValue;
34

45
fn main() {
56
App::new()
67
.add_plugins(DefaultPlugins)
78
.add_plugins(neko_maid::NekoMaidPlugin)
89
.add_systems(Startup, setup)
10+
.add_systems(FixedUpdate, update_color)
911
.run();
1012
}
1113

@@ -15,3 +17,14 @@ fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
1517
let handle = asset_server.load("example.neko_ui");
1618
commands.spawn(NekoUITree::new(handle));
1719
}
20+
21+
pub fn update_color(time: Res<Time>, mut q: Query<&mut NekoUITree>) {
22+
for mut root in &mut q {
23+
let h = (time.elapsed_secs_f64() % 4.0) / 4.0 * 360.0;
24+
let color = Color::hsl(h as f32, 0.5, 0.3);
25+
root.set_variable("color", PropertyValue::Color(color));
26+
27+
let width = 400.0 + f64::sin(time.elapsed_secs_f64()) * 100.0;
28+
root.set_variable("width", PropertyValue::Number(width));
29+
}
30+
}

examples/slots.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use bevy::prelude::*;
2+
use neko_maid::components::NekoUITree;
3+
4+
fn main() {
5+
App::new()
6+
.add_plugins(DefaultPlugins)
7+
.add_plugins(neko_maid::NekoMaidPlugin)
8+
.add_systems(Startup, setup)
9+
.run();
10+
}
11+
12+
fn setup(asset_server: Res<AssetServer>, mut commands: Commands) {
13+
commands.spawn(Camera2d);
14+
15+
let handle = asset_server.load("slots.neko_ui");
16+
commands.spawn(NekoUITree::new(handle));
17+
}

neko_derive/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "neko_derive"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
proc-macro = true
8+
9+
[dependencies]
10+
syn = { version = "2", features = ["full"] }
11+
quote = "1"
12+
proc-macro2 = "1"

neko_derive/src/lib.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use proc_macro::TokenStream;
2+
use quote::quote;
3+
use syn::{DeriveInput, LitStr, parse_macro_input};
4+
5+
#[proc_macro_derive(NekoMarker, attributes(neko_marker))]
6+
pub fn derive_neko_marker(input: TokenStream) -> TokenStream {
7+
let input = parse_macro_input!(input as DeriveInput);
8+
let ident = &input.ident;
9+
10+
// Find #[neko_marker("...")]
11+
let mut marker_value: Option<LitStr> = None;
12+
13+
for attr in &input.attrs {
14+
if attr.path().is_ident("neko_marker") {
15+
let lit: LitStr = attr
16+
.parse_args()
17+
.expect("neko_marker expects a string literal");
18+
marker_value = Some(lit);
19+
}
20+
}
21+
22+
let marker_value = marker_value.expect("Missing #[neko_marker(\"...\")] attribute");
23+
24+
let expanded = quote! {
25+
impl NekoMarker for #ident {
26+
fn new() -> Self {
27+
Self
28+
}
29+
30+
fn id() -> &'static str {
31+
#marker_value
32+
}
33+
}
34+
};
35+
36+
expanded.into()
37+
}

0 commit comments

Comments
 (0)