This commit is contained in:
2025-07-15 17:13:35 +01:00
parent 1117ce9f13
commit fe8bbae68e
11 changed files with 201 additions and 49 deletions
+5
View File
@@ -22,3 +22,8 @@ thiserror = "2.0.12"
egui_commonmark = { version = "0.20.0", features = ["embedded_image"] }
walkdir = "2.5.0"
uuid = { version = "1.17.0", features = ["v4"] }
[target.x86_64-pc-windows-gnu]
linker = "x86_64-w64-mingw32-gcc"
ar = "x86_64-w64-mingw32-gcc-ar"
@@ -0,0 +1,4 @@
{
"name": "New Document",
"text": "# The effects of Whimsum dust:\nmore aggression, higher damage, higher rate of fire, lower accuracy"
}
@@ -0,0 +1,10 @@
{
"id": "0078bb24-2fb0-4ecb-b5cb-20d29c5f2f77",
"template_id": "b5745688-3c1c-40de-bc3a-2a3e354dd19d",
"name": "The SPOONS!",
"fields": {
"description": {
"value": "full of smilers\n"
}
}
}
@@ -0,0 +1,10 @@
{
"id": "20beeb2f-363c-49bf-9621-f156d7c7cdd7",
"template_id": "b5745688-3c1c-40de-bc3a-2a3e354dd19d",
"name": "the brewdog.",
"fields": {
"description": {
"value": "full of smilers\n"
}
}
}
@@ -1,16 +0,0 @@
{
"id": "67e29043-9aa8-4dd9-807c-cc7385eb6847",
"template_id": "c96f5e87-7517-44cc-a5ab-42ffd537801d",
"name": "sword",
"fields": {
"durability": {
"value": "8.6"
},
"Icon": {
"value": "/home/zxq5/Projects/Minecraft/Packs/ZXQ5 projects/ZXQ5 x/ZXQ5 x-512/ZXQ5 x Release/classic.pack.png"
},
"description": {
"value": "idk"
}
}
}
@@ -0,0 +1,16 @@
{
"id": "bd13d252-3f19-4618-bb10-cc45e9f7d301",
"template_id": "c96f5e87-7517-44cc-a5ab-42ffd537801d",
"name": "Cast Iron Pan",
"fields": {
"durability": {
"value": "9999999"
},
"Icon": {
"value": ""
},
"description": {
"value": "An unburnt pan for bitchslapping, comes with a free punchcard."
}
}
}
@@ -1,22 +0,0 @@
{
"id": "d1b10e0c-f6b4-4b9d-a96e-cb51213f0243",
"template_id": "a24b3ab7-2572-4af4-8457-df26937fd773",
"name": "zxq5",
"fields": {
"Personality": {
"value": "coder"
},
"Portrait / Image": {
"value": "/home/fantasypvp/Pictures/logos and pfps/YT profile picture background.png"
},
"Appearance": {
"value": "taller than panic"
},
"Age": {
"value": "19"
},
"Date of Birth": {
"value": "2025-07-15"
}
}
}
+4 -2
View File
@@ -10,13 +10,15 @@
- [x] Edit template
- [x] Save template
- [x] Load template
- [ ] Delete template
- [x] Delete template
- [x] Create copy of template
- [x] Objects
- [x] Create object from template
- [x] Save object
- [x] Load object
- [x] View & Edit Object
- [ ] Delete object
- [x] Delete object
- [x] Create copy of object
- [x] Projects
- [x] Single project folder (hardcoded at current directory)
+35 -2
View File
@@ -2,6 +2,7 @@ use egui::RichText;
use crate::{
PROJECT_FOLDER, RightPanelContent,
main_editor::MainEditor,
note::Note,
object::ObjectInstance,
template::{FieldType, Template},
@@ -14,7 +15,12 @@ impl Explorer {
Self {}
}
pub fn ui(&mut self, to_load: &mut Option<RightPanelContent>, ui: &mut egui::Ui) {
pub fn ui(
&mut self,
to_load: &mut Option<RightPanelContent>,
load_doc: &mut Option<MainEditor>,
ui: &mut egui::Ui,
) {
let (templates, objects) = match Self::load_templates() {
Ok((templates, objects)) => (templates, objects),
Err(e) => {
@@ -116,7 +122,20 @@ impl Explorer {
}
});
egui::CollapsingHeader::new("Projects").show(ui, |ui| {});
let documents = Self::load_documents().unwrap();
egui::CollapsingHeader::new("Projects").show(ui, |ui| {
for document in &documents {
ui.horizontal(|ui| {
ui.add_space(10.0);
// load the document
if ui.selectable_label(false, &document.name).clicked() {
*load_doc = Some(document.clone());
}
});
}
});
});
}
@@ -156,4 +175,18 @@ impl Explorer {
Ok(notes)
}
fn load_documents() -> std::io::Result<Vec<MainEditor>> {
let mut documents = Vec::new();
for entry in std::fs::read_dir(PROJECT_FOLDER.join("documents")).unwrap() {
let path = entry.unwrap().path();
match MainEditor::load(path.file_stem().unwrap().to_str().unwrap()) {
Ok(document) => documents.push(document),
Err(err) => eprintln!("Could not parse file {path:?}: {err}"),
}
}
Ok(documents)
}
}
+9 -2
View File
@@ -13,7 +13,7 @@ use egui_file::DialogType;
use object::ObjectInstance;
use template::{FieldType, Template};
use crate::{explorer::Explorer, note::Note};
use crate::{explorer::Explorer, main_editor::MainEditor, note::Note};
static PROJECT_FOLDER: LazyLock<PathBuf> = LazyLock::new(|| {
let mut path = std::env::current_dir().unwrap();
@@ -147,14 +147,21 @@ impl eframe::App for Interface {
ui.separator();
let mut to_load: Option<RightPanelContent> = None;
let mut load_doc: Option<MainEditor> = None;
ScrollArea::vertical().show(ui, |ui| {
self.explorer.ui(&mut to_load, ui);
self.explorer.ui(&mut to_load, &mut load_doc, ui);
});
if let Some(to_load) = to_load {
self.right_panel_content = to_load;
}
if let Some(load_doc) = load_doc {
self.editor = load_doc;
self.editor.show_editor = true;
self.editor.show_preview = true;
}
});
// Main content area
+108 -5
View File
@@ -1,32 +1,133 @@
use egui::{TextEdit, Ui};
use egui::{RichText, TextEdit, Ui};
use egui_commonmark::{CommonMarkCache, CommonMarkViewer};
use serde::{self, Deserialize, Serialize};
use crate::PROJECT_FOLDER;
#[derive(Serialize, Deserialize)]
pub struct MainEditor {
pub name: String,
pub text: String,
#[serde(skip)]
pub id: String,
#[serde(skip)]
saved: bool,
#[serde(skip)]
pub show_editor: bool,
#[serde(skip)]
pub show_preview: bool,
text: String,
#[serde(skip)]
preview_cache: CommonMarkCache,
}
impl Clone for MainEditor {
fn clone(&self) -> Self {
Self {
name: self.name.clone(),
text: self.text.clone(),
id: self.id.clone(),
saved: self.saved,
show_editor: self.show_editor,
show_preview: self.show_preview,
preview_cache: CommonMarkCache::default(),
}
}
}
impl MainEditor {
pub fn new() -> Self {
Self {
text: String::new(),
id: uuid::Uuid::new_v4().to_string(),
name: "New Document".to_string(),
saved: false,
show_editor: false, // Start with editor hidden
show_preview: true,
text: String::new(),
preview_cache: CommonMarkCache::default(),
}
}
pub fn load(id: &str) -> Result<Self, Box<dyn std::error::Error>> {
let path = PROJECT_FOLDER
.join("documents")
.join(format!("{}.json", id));
let content = std::fs::read_to_string(&path)?;
let mut editor: Self = serde_json::from_str(&content)?;
editor.saved = true;
editor.id = id.to_string();
Ok(editor)
}
pub fn save(&mut self) -> Result<(), Box<dyn std::error::Error>> {
let path = PROJECT_FOLDER
.join("documents")
.join(format!("{}.json", &self.id));
let content = serde_json::to_string_pretty(self)?;
std::fs::write(path, content)?;
self.saved = true;
Ok(())
}
pub fn ui(&mut self, ctx: &egui::Context) {
// Show the editor window if enabled
if self.show_editor {
let mut show = self.show_editor;
if show {
egui::Window::new("Markdown Editor")
.resizable(true)
.default_width(1000.0)
.default_height(800.0)
.open(&mut self.show_editor)
.open(&mut show)
.show(ctx, |ui| {
ui.vertical(|ui| {
ui.group(|ui| {
ui.horizontal(|ui| {
if self.saved {
ui.label(RichText::new("✓ Saved").color(egui::Color32::GREEN));
} else {
ui.label(
RichText::new("* Unsaved").color(egui::Color32::YELLOW),
);
}
ui.label(format!("id: {}", self.id));
});
});
// Save/Cancel buttons
ui.horizontal(|ui| {
if ui.button("Save").clicked() {
if let Err(e) = self.save() {
eprintln!("Failed to save: {e}");
}
}
if ui.button("Create Copy").clicked() {
let mut copy = self.clone();
copy.id = uuid::Uuid::new_v4().to_string();
copy.name = format!("{} (Copy)", self.name);
copy.save().unwrap();
}
if ui.button("Delete").clicked() {
std::fs::remove_file(
PROJECT_FOLDER
.join("documents")
.join(format!("{}.json", self.id)),
)
.unwrap();
*self = Self::new();
}
if ui.button("Revert changes").clicked() {
// load default state
*self = Self::load(&self.id).unwrap();
}
});
});
ui.horizontal(|ui| {
ui.label("Content Editor");
ui.checkbox(&mut self.show_preview, "Preview");
@@ -104,5 +205,7 @@ impl MainEditor {
});
});
}
self.show_editor = show;
}
}