diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
index 8f3eeda..f74a329 100644
--- a/src-tauri/Cargo.toml
+++ b/src-tauri/Cargo.toml
@@ -17,7 +17,7 @@ tauri-build = { version = "1.5.2", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
-tauri = { version = "1.6.5", features = [ "dialog-all", "fs-all"] }
+tauri = { version = "1.6.5", features = [ "window-start-dragging", "dialog-all", "fs-all"] }
[features]
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs
index e6ad770..4d65897 100644
--- a/src-tauri/src/main.rs
+++ b/src-tauri/src/main.rs
@@ -1,8 +1,101 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
+use std::any::Any;
+
+use tauri::{AboutMetadata, CustomMenuItem, Menu, MenuEntry, MenuItem, Submenu};
+
+#[derive(Clone, serde::Serialize)]
+struct OpenFolderMessage {}
+
fn main() {
+ let menu = build_menu("BufPiv");
tauri::Builder::default()
+ .menu(menu)
+ .on_menu_event(|event| match event.menu_item_id() {
+ "openfolder" => {
+ event
+ .window()
+ .emit("openfolder", OpenFolderMessage {})
+ .expect("Failed to emit openfolder event");
+ }
+ _ => {}
+ })
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
+
+fn build_menu(app_name: &str) -> Menu {
+ let mut menu = Menu::new();
+ #[cfg(target_os = "macos")]
+ {
+ menu = menu.add_submenu(Submenu::new(
+ app_name,
+ Menu::new()
+ .add_native_item(MenuItem::About(
+ app_name.to_string(),
+ AboutMetadata::default(),
+ ))
+ .add_native_item(MenuItem::Separator)
+ .add_native_item(MenuItem::Services)
+ .add_native_item(MenuItem::Separator)
+ .add_native_item(MenuItem::Hide)
+ .add_native_item(MenuItem::HideOthers)
+ .add_native_item(MenuItem::ShowAll)
+ .add_native_item(MenuItem::Separator)
+ .add_native_item(MenuItem::Quit),
+ ));
+ }
+ let open_folder =
+ CustomMenuItem::new("openfolder".to_string(), "Open Folder").accelerator("cmd+shift+O");
+ let file_submenu = Menu::new()
+ .add_item(open_folder)
+ .add_native_item(MenuItem::CloseWindow);
+ #[cfg(not(target_os = "macos"))]
+ {
+ file_submenu = file_submenu.add_native_item(MenuItem::Quit);
+ }
+ menu = menu.add_submenu(Submenu::new("File", file_submenu));
+
+ #[cfg(not(target_os = "linux"))]
+ let mut edit_menu = Menu::new();
+ #[cfg(target_os = "macos")]
+ {
+ edit_menu = edit_menu.add_native_item(MenuItem::Undo);
+ edit_menu = edit_menu.add_native_item(MenuItem::Redo);
+ edit_menu = edit_menu.add_native_item(MenuItem::Separator);
+ }
+ #[cfg(not(target_os = "linux"))]
+ {
+ edit_menu = edit_menu.add_native_item(MenuItem::Cut);
+ edit_menu = edit_menu.add_native_item(MenuItem::Copy);
+ edit_menu = edit_menu.add_native_item(MenuItem::Paste);
+ }
+ #[cfg(target_os = "macos")]
+ {
+ edit_menu = edit_menu.add_native_item(MenuItem::SelectAll);
+ }
+ #[cfg(not(target_os = "linux"))]
+ {
+ menu = menu.add_submenu(Submenu::new("Edit", edit_menu));
+ }
+ #[cfg(target_os = "macos")]
+ {
+ menu = menu.add_submenu(Submenu::new(
+ "View",
+ Menu::new().add_native_item(MenuItem::EnterFullScreen),
+ ));
+ }
+
+ let mut window_menu = Menu::new();
+ window_menu = window_menu.add_native_item(MenuItem::Minimize);
+ #[cfg(target_os = "macos")]
+ {
+ window_menu = window_menu.add_native_item(MenuItem::Zoom);
+ window_menu = window_menu.add_native_item(MenuItem::Separator);
+ }
+ window_menu = window_menu.add_native_item(MenuItem::CloseWindow);
+ menu = menu.add_submenu(Submenu::new("Window", window_menu));
+
+ menu
+}
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index c9de89f..6c95f89 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -7,7 +7,7 @@
"distDir": "../dist"
},
"package": {
- "productName": "Piv's Buf",
+ "productName": "BufPiv",
"version": "0.0.0"
},
"tauri": {
@@ -18,16 +18,48 @@
},
"dialog": {
"all": true
+ },
+ "window": {
+ "all": false,
+ "center": false,
+ "close": false,
+ "create": false,
+ "hide": false,
+ "maximize": false,
+ "minimize": false,
+ "print": false,
+ "requestUserAttention": false,
+ "setAlwaysOnTop": false,
+ "setClosable": false,
+ "setContentProtected": false,
+ "setCursorGrab": false,
+ "setCursorIcon": false,
+ "setCursorPosition": false,
+ "setCursorVisible": false,
+ "setDecorations": false,
+ "setFocus": false,
+ "setFullscreen": false,
+ "setIcon": false,
+ "setIgnoreCursorEvents": false,
+ "setMaxSize": false,
+ "setMaximizable": false,
+ "setMinSize": false,
+ "setMinimizable": false,
+ "setPosition": false,
+ "setResizable": false,
+ "setSize": false,
+ "setSkipTaskbar": false,
+ "setTitle": false,
+ "show": false,
+ "startDragging": true,
+ "unmaximize": false,
+ "unminimize": false
}
},
"bundle": {
"active": true,
"category": "DeveloperTool",
- "copyright": "",
- "deb": {
- "depends": []
- },
- "externalBin": [],
+ "copyright": "Michael Pivato 2024",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
@@ -36,7 +68,7 @@
"icons/icon.ico"
],
"identifier": "dev.michaelpivato",
- "longDescription": "",
+ "longDescription": "Create and edit protobuf and json files based on protobuf definitions.",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
@@ -64,8 +96,10 @@
"fullscreen": false,
"height": 600,
"resizable": true,
- "title": "Piv's Buf",
- "width": 800
+ "title": "BufPiv",
+ "hiddenTitle": true,
+ "width": 800,
+ "titleBarStyle": "Overlay"
}
]
}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index 1b95e64..7fa7c18 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,11 +1,26 @@
-BufPiv
+BufPiv
+ @if(selectedDirectory()) {
+ }
- @if (!selectedDirectory) {
-
+ @if (!selectedDirectory()) {
+
+
+
}@else { }
diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index c4d7999..5011c3d 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -3,6 +3,12 @@
flex-direction: column;
height: 100%;
}
+
+mat-toolbar {
+ flex: 0 0 auto;
+ padding-top: 24px;
+ --mat-toolbar-standard-height: 70px;
+}
mat-sidenav-container {
width: 100%;
height: 100%;
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 042baaf..89da95e 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,5 +1,11 @@
import { CommonModule } from '@angular/common';
-import { Component, signal } from '@angular/core';
+import {
+ ChangeDetectorRef,
+ Component,
+ OnDestroy,
+ OnInit,
+ signal,
+} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatSidenavModule } from '@angular/material/sidenav';
import { RouterOutlet } from '@angular/router';
@@ -12,6 +18,8 @@ import {
FileTreeComponent,
} from './file-tree/file-tree.component';
import { MatIconModule } from '@angular/material/icon';
+import { listen, UnlistenFn } from '@tauri-apps/api/event';
+import { OpenFolderMessage } from './messages/openfolder.message';
@Component({
selector: 'app-root',
@@ -30,9 +38,26 @@ import { MatIconModule } from '@angular/material/icon';
],
})
export class AppComponent {
- protected selectedDirectory: string | null = null;
+ protected selectedDirectory = signal(null);
protected files = signal([]);
+ private unlisten?: UnlistenFn;
+
+ async ngOnInit() {
+ this.unlisten = await listen(
+ 'openfolder',
+ async (event: OpenFolderMessage) => {
+ await this.selectDirectory();
+ }
+ );
+ }
+
+ async ngOnDestroy() {
+ if (this.unlisten) {
+ this.unlisten();
+ }
+ }
+
async selectDirectory() {
const selectedDirectory = await open({
directory: true,
@@ -40,22 +65,58 @@ export class AppComponent {
});
if (Array.isArray(selectedDirectory)) {
message('Only a single folder can be selected at a time');
+ return;
} else {
- this.selectedDirectory = selectedDirectory;
+ this.selectedDirectory.set(selectedDirectory);
}
- if (this.selectedDirectory) {
- const entries = await readDir(this.selectedDirectory, {
+ if (selectedDirectory) {
+ const entries = await readDir(selectedDirectory, {
recursive: true,
});
- this.files.set(entries.map((entry) => this.mapEntry(entry)));
+ const splitNumbers = /(\d)+|(\D)+/;
+ this.files.set(
+ entries
+ .sort(this.sortFiles(splitNumbers))
+ .map((entry) => this.mapEntry(entry, splitNumbers))
+ );
}
}
- private mapEntry(entry: FileEntry): FileOrFolder {
+ private mapEntry(entry: FileEntry, splitNumbers: RegExp): FileOrFolder {
return {
isDirectory: entry.children != null,
name: entry.name || '',
- children: entry.children?.map((entry) => this.mapEntry(entry)),
+ children: entry.children?.map((entry) =>
+ this.mapEntry(entry, splitNumbers)
+ ),
};
}
+
+ private sortFiles =
+ (splitNumbers: RegExp) => (a: FileEntry, b: FileEntry) => {
+ return a.name?.localeCompare(b.name ?? '') ?? 0;
+ // if (!a.name) {
+ // return -1;
+ // }
+ // if (!b.name) {
+ // return 1;
+ // }
+ // const aSplit = splitNumbers.exec(a.name);
+ // const bSplit = splitNumbers.exec(b.name);
+ // if (!aSplit) {
+ // return -1;
+ // }
+ // if (!bSplit) {
+ // return 1;
+ // }
+ // for (
+ // let i = 0;
+ // i < (aSplit.length > bSplit.length ? bSplit.length : aSplit.length);
+ // i++
+ // ) {}
+ // // TODO: Alternative is to iterate through characters in the strings to find numbers, if there isn't a number then return
+ // // locale compare?
+ // // TODO: finish this
+ // return 0;
+ };
}
diff --git a/src/app/file-tree/file-tree.component.ts b/src/app/file-tree/file-tree.component.ts
index f98faf2..dc4a908 100644
--- a/src/app/file-tree/file-tree.component.ts
+++ b/src/app/file-tree/file-tree.component.ts
@@ -40,7 +40,7 @@ interface FileNode {
{{ node.file.name }}
-
+
- {{ node.name }}
+ {{ node.file.name }}
`,
styleUrl: './file-tree.component.scss',
diff --git a/src/app/messages/openfolder.message.ts b/src/app/messages/openfolder.message.ts
new file mode 100644
index 0000000..97174b0
--- /dev/null
+++ b/src/app/messages/openfolder.message.ts
@@ -0,0 +1 @@
+export interface OpenFolderMessage {}
diff --git a/src/m3-theme.scss b/src/m3-theme.scss
deleted file mode 100644
index 55f4d04..0000000
--- a/src/m3-theme.scss
+++ /dev/null
@@ -1,141 +0,0 @@
-// This file was generated by running 'ng generate @angular/material:m3-theme'.
-// Proceed with caution if making changes to this file.
-
-@use 'sass:map';
-@use '@angular/material' as mat;
-
-// Note: Color palettes are generated from primary: #DF6B85, secondary: #AE868D, tertiary: #B48858, neutral: #988E8F
-$_palettes: (
- primary: (
- 0: #000000,
- 10: #3f0015,
- 20: #630828,
- 25: #721633,
- 30: #82233e,
- 35: #912f49,
- 40: #a13a54,
- 50: #c0536c,
- 60: #e06c86,
- 70: #ff86a0,
- 80: #ffb2bf,
- 90: #ffd9de,
- 95: #ffecee,
- 98: #fff8f7,
- 99: #fffbff,
- 100: #ffffff,
- ),
- secondary: (
- 0: #000000,
- 10: #3f0017,
- 20: #5f112b,
- 25: #6d1d35,
- 30: #7c2940,
- 35: #8b344c,
- 40: #9a4058,
- 50: #b95870,
- 60: #d87189,
- 70: #f78aa3,
- 80: #ffb1c0,
- 90: #ffd9df,
- 95: #ffecee,
- 98: #fff8f7,
- 99: #fffbff,
- 100: #ffffff,
- ),
- tertiary: (
- 0: #000000,
- 10: #2b1700,
- 20: #482900,
- 25: #573300,
- 30: #673d00,
- 35: #774700,
- 40: #885200,
- 50: #aa6800,
- 60: #c98121,
- 70: #e89b3a,
- 80: #ffb868,
- 90: #ffddbb,
- 95: #ffeedf,
- 98: #fff8f4,
- 99: #fffbff,
- 100: #ffffff,
- ),
- neutral: (
- 0: #000000,
- 10: #3f0018,
- 20: #5f112c,
- 25: #6d1d37,
- 30: #7c2942,
- 35: #8b344e,
- 40: #9a4059,
- 50: #b85872,
- 60: #d7718b,
- 70: #f78aa5,
- 80: #ffb1c2,
- 90: #ffd9e0,
- 95: #ffecee,
- 98: #fff8f7,
- 99: #fffbff,
- 100: #ffffff,
- ),
- neutral-variant: (
- 0: #000000,
- 10: #24191a,
- 20: #3a2d2f,
- 25: #46383a,
- 30: #524345,
- 35: #5e4f51,
- 40: #6a5a5c,
- 50: #847375,
- 60: #9f8c8e,
- 70: #baa6a9,
- 80: #d6c2c4,
- 90: #f3dddf,
- 95: #ffecee,
- 98: #fff8f7,
- 99: #fffbff,
- 100: #ffffff,
- ),
- error: (
- 0: #000000,
- 10: #410002,
- 20: #690005,
- 25: #7e0007,
- 30: #93000a,
- 35: #a80710,
- 40: #ba1a1a,
- 50: #de3730,
- 60: #ff5449,
- 70: #ff897d,
- 80: #ffb4ab,
- 90: #ffdad6,
- 95: #ffedea,
- 98: #fff8f7,
- 99: #fffbff,
- 100: #ffffff,
- ),
-);
-
-$_rest: (
- secondary: map.get($_palettes, secondary),
- neutral: map.get($_palettes, neutral),
- neutral-variant: map.get($_palettes, neutral-variant),
- error: map.get($_palettes, error),
-);
-$_primary: map.merge(map.get($_palettes, primary), $_rest);
-$_tertiary: map.merge(map.get($_palettes, tertiary), $_rest);
-
-$light-theme: mat.define-theme((
- color: (
- theme-type: light,
- primary: $_primary,
- tertiary: $_tertiary,
- ),
-));
-$dark-theme: mat.define-theme((
- color: (
- theme-type: dark,
- primary: $_primary,
- tertiary: $_tertiary,
- ),
-));
\ No newline at end of file
diff --git a/src/styles.scss b/src/styles.scss
index 136375c..ac94bab 100644
--- a/src/styles.scss
+++ b/src/styles.scss
@@ -1,10 +1,17 @@
-@use '@angular/material' as mat;
-@use './m3-theme.scss';
+@use "@angular/material" as mat;
+@use "./theme.scss";
@include mat.core();
+@mixin custom-colours($theme) {
+ .mat-toolbar {
+ background-color: mat.get-theme-color($theme, primary-container);
+ }
+}
+
html {
- @include mat.all-component-themes(m3-theme.$dark-theme);
+ @include mat.all-component-themes(theme.$rose-theme);
+ @include custom-colours(theme.$rose-theme);
}
html,
diff --git a/src/theme.scss b/src/theme.scss
new file mode 100644
index 0000000..a94eeb8
--- /dev/null
+++ b/src/theme.scss
@@ -0,0 +1,10 @@
+@use "@angular/material" as mat;
+
+$rose-theme: mat.define-theme(
+ (
+ color: (
+ theme-type: dark,
+ primary: mat.$rose-palette,
+ ),
+ )
+);