113 lines
3.6 KiB
Rust
113 lines
3.6 KiB
Rust
use chara::CharacterDefinition;
|
|
use maud::{Markup, html};
|
|
|
|
pub fn render_character(def: &CharacterDefinition, relative_path: &str) -> Markup {
|
|
let relative_path = relative_path.rsplit_once('/');
|
|
let relative_path = relative_path.map_or("", |(l, _r)| l);
|
|
|
|
html! {
|
|
style { (CHARACTER_CSS) }
|
|
|
|
div.customizer-container {
|
|
div.character-container {
|
|
@for layer in &def.layers {
|
|
img.character-layer
|
|
id=(format!("{}-layer", layer.internal_name))
|
|
src=(layer.entries.first().map(|e| format!("/{relative_path}/{}", e.path)).unwrap_or_default())
|
|
style=(format!("display: {};",
|
|
if !layer.entries.is_empty() && !layer.entries[0].path.is_empty() {
|
|
"block"
|
|
} else {
|
|
"none"
|
|
}
|
|
));
|
|
}
|
|
}
|
|
|
|
div.controls-column {
|
|
@for layer in &def.layers {
|
|
@if let Some(display_name) = &layer.display_name {
|
|
div.layer-group {
|
|
div.layer-title { (display_name) }
|
|
div.layer-options {
|
|
@for (i, entry) in layer.entries.iter().enumerate() {
|
|
label.option {
|
|
input type="radio"
|
|
name=(layer.internal_name)
|
|
value=(entry.path)
|
|
checked[i==0]
|
|
onchange=(format!(
|
|
"var img=document.getElementById('{}-layer');img.src=this.value;img.style.display=this.value==''?'none':'block';",
|
|
layer.internal_name
|
|
));
|
|
(entry.name)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const CHARACTER_CSS: &str = r"
|
|
.customizer-container { display: flex; gap: 20px; margin-top: 20px; }
|
|
.character-container {
|
|
position: relative;
|
|
width: 300px;
|
|
height: 400px;
|
|
border: 2px solid #ddd;
|
|
border-radius: 10px;
|
|
background-color: white;
|
|
flex-shrink: 0;
|
|
}
|
|
.character-layer {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
object-fit: contain;
|
|
}
|
|
.controls-column {
|
|
flex-grow: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 15px;
|
|
}
|
|
.layer-group {
|
|
background-color: white;
|
|
padding: 15px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
}
|
|
.layer-title {
|
|
font-weight: bold;
|
|
margin-bottom: 10px;
|
|
color: #333;
|
|
}
|
|
.layer-options {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
gap: 8px;
|
|
}
|
|
.option {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.option input {
|
|
margin-right: 8px;
|
|
}
|
|
.back-link {
|
|
display: inline-block;
|
|
margin-bottom: 15px;
|
|
color: #333;
|
|
text-decoration: none;
|
|
}
|
|
.back-link:hover {
|
|
text-decoration: underline;
|
|
}
|
|
";
|