126 lines
5.4 KiB
Rust
126 lines
5.4 KiB
Rust
use std::{ops::Deref, rc::Rc};
|
|
|
|
use itertools::Itertools;
|
|
use web_sys::{KeyboardEvent, MouseEvent};
|
|
use yew::{function_component, html, AttrValue, Html, UseStateHandle};
|
|
|
|
use super::{close_editor, run_script, select_file, EditorViewDetailProps, EditorViewState};
|
|
|
|
fn show_create_dialog(state: &UseStateHandle<Rc<EditorViewState>>) {
|
|
let mut new_state: EditorViewState = (*state.deref().deref()).clone();
|
|
new_state.show_create_dialog = true;
|
|
state.set(new_state.into());
|
|
}
|
|
|
|
fn item_keyboard_handler(
|
|
item: AttrValue,
|
|
editor_state: UseStateHandle<Rc<EditorViewState>>,
|
|
) -> impl Fn(KeyboardEvent) {
|
|
move |ev: KeyboardEvent| {
|
|
if ev.code() == "Enter" && !ev.get_modifier_state("Control") {
|
|
let mut state_mut = (*editor_state.as_ref()).clone();
|
|
state_mut.open_file = item.clone();
|
|
editor_state.set(state_mut.into());
|
|
} else if ev.code() == "ArrowUp" {
|
|
if let Some((pos, _)) = editor_state
|
|
.available_files
|
|
.iter()
|
|
.find_position(|v| **v == editor_state.open_file)
|
|
{
|
|
if pos > 0 {
|
|
let mut state_mut = (*editor_state.as_ref()).clone();
|
|
state_mut.open_file = editor_state.available_files[pos - 1].clone();
|
|
editor_state.set(state_mut.into());
|
|
}
|
|
}
|
|
} else if ev.code() == "ArrowDown" {
|
|
if let Some((pos, _)) = editor_state
|
|
.available_files
|
|
.iter()
|
|
.find_position(|v| **v == editor_state.open_file)
|
|
{
|
|
if pos < editor_state.available_files.len() - 1 {
|
|
let mut state_mut = (*editor_state.as_ref()).clone();
|
|
state_mut.open_file = editor_state.available_files[pos + 1].clone();
|
|
editor_state.set(state_mut.into());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn show_delete_dialog(state: &UseStateHandle<Rc<EditorViewState>>, script: &AttrValue) {
|
|
let mut new_state = (*state.as_ref()).clone();
|
|
new_state.show_delete_dialog = Some(script.clone());
|
|
state.set(new_state.into());
|
|
}
|
|
|
|
#[function_component(EditorNav)]
|
|
pub(super) fn editor_nav(props: &EditorViewDetailProps) -> Html {
|
|
let global_memo = props.global_memo.clone();
|
|
let global_layout = props.global_layout.clone();
|
|
let frame = props.frame.clone();
|
|
let current_script = props.editor_state.open_file.clone();
|
|
|
|
let set_err_state = props.editor_state.clone();
|
|
let set_err = Rc::new(move |msg: Option<&str>| {
|
|
let mut new_state = (*set_err_state.as_ref()).clone();
|
|
new_state.error_msg = msg.map(|v| AttrValue::from(String::from(v)));
|
|
set_err_state.set(new_state.into());
|
|
});
|
|
let editor_state = props.editor_state.clone();
|
|
let frame_for_runclick = frame.clone();
|
|
html! {
|
|
<div class="editornav">
|
|
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
|
<button class="btn" aria-label="Run" title="Run"
|
|
onclick={move |_ev| run_script(¤t_script, &global_memo, set_err.clone(), &frame_for_runclick)}>
|
|
<i class="bi bi-file-earmark-play"></i></button>
|
|
<button class="btn" aria-label="New file" title="New file"
|
|
onclick={move |_ev| show_create_dialog(&editor_state) }
|
|
><i class="bi bi-file-earmark-plus"></i></button>
|
|
<div class="flex-fill"/>
|
|
<button class="btn" onclick={move |_ev| close_editor(&frame, &global_layout)} aria-label="Close Editor" title="Close editor"><i class="bi bi-arrow-return-left"></i></button>
|
|
</nav>
|
|
<ul class="p-2 list-group">
|
|
{props
|
|
.editor_state
|
|
.available_files
|
|
.iter()
|
|
.map(|f| {
|
|
let mut classes = vec!["list-group-item", "d-flex"];
|
|
let mut aria_current = None;
|
|
if *f == props.editor_state.open_file {
|
|
aria_current = Some("true");
|
|
classes.push("active");
|
|
}
|
|
let filename_for_click: AttrValue = f.clone();
|
|
let state_for_click = props.editor_state.clone();
|
|
let filename_for_kb: AttrValue = f.clone();
|
|
let state_for_kb = props.editor_state.clone();
|
|
let state_for_delscript = state_for_kb.clone();
|
|
let filename_for_delscript: AttrValue = f.clone();
|
|
html! { <li aria-current={aria_current}
|
|
class={classes.iter().join(" ")}
|
|
>
|
|
<div tabindex={0}
|
|
class="pe-auto"
|
|
onkeydown={item_keyboard_handler(filename_for_kb, state_for_kb)}
|
|
style="cursor: pointer"
|
|
onclick={move |_ev| select_file(&filename_for_click, &state_for_click)}>{f}</div>
|
|
<div class="flex-fill"/>
|
|
{if f != "init.lua" {
|
|
html! { <button class="btn" onclick={move |ev: MouseEvent| {
|
|
show_delete_dialog(&state_for_delscript, &filename_for_delscript);
|
|
ev.prevent_default();
|
|
}} aria-label="Delete" title="Delete"><i class="bi bi-trash"></i></button> }
|
|
} else { html!{<></>} } }
|
|
</li>}
|
|
})
|
|
.collect::<Vec<Html>>()
|
|
}
|
|
</ul>
|
|
</div>
|
|
}
|
|
}
|