├── src-tauri
├── scripts
│ ├── .gitkeep
│ └── owoifier.js
├── build.rs
├── assets
│ └── UI.png
├── icons
│ ├── icon.ico
│ ├── 128x128.png
│ ├── 32x32.png
│ ├── 512x512.png
│ ├── 64x64.png
│ ├── icon.icns
│ ├── 128x128@2x.png
│ ├── setupBanner.bmp
│ └── setupBackground.bmp
├── src
│ ├── assets
│ │ └── UI.png
│ ├── icons
│ │ ├── 32x32.png
│ │ ├── 64x64.png
│ │ ├── icon.icns
│ │ ├── icon.ico
│ │ ├── 128x128.png
│ │ ├── 512x512.png
│ │ ├── 128x128@2x.png
│ │ ├── setupBanner.bmp
│ │ └── setupBackground.bmp
│ ├── config
│ │ └── default.toml
│ ├── settings.rs
│ ├── main.rs
│ └── scripts.rs
├── app
│ ├── stylesheets
│ │ ├── base
│ │ │ ├── _helpers.scss
│ │ │ └── _base.scss
│ │ ├── main.scss
│ │ └── components
│ │ │ ├── _window.scss
│ │ │ ├── _editor.scss
│ │ │ ├── _spotlight.scss
│ │ │ ├── _titlebar.scss
│ │ │ └── _icons.scss
│ ├── js
│ │ ├── components
│ │ │ ├── action.ts
│ │ │ ├── editor.ts
│ │ │ ├── titlebar.ts
│ │ │ ├── settings.ts
│ │ │ ├── editorObj.ts
│ │ │ ├── bloopMode.ts
│ │ │ └── spotlight.ts
│ │ └── app.ts
│ ├── index.html
│ └── icons
│ │ └── cog.svg
├── rustfmt.toml
├── config
│ └── default.toml
├── Cargo.toml
└── tauri.conf.json
├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── .gitignore
├── vite.config.ts
├── package.json
└── README.md
/src-tauri/scripts/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src-tauri/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | tauri_build::build()
3 | }
4 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | ko_fi: blainesensei
4 |
--------------------------------------------------------------------------------
/src-tauri/assets/UI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/assets/UI.png
--------------------------------------------------------------------------------
/src-tauri/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/icon.ico
--------------------------------------------------------------------------------
/src-tauri/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/128x128.png
--------------------------------------------------------------------------------
/src-tauri/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/32x32.png
--------------------------------------------------------------------------------
/src-tauri/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/512x512.png
--------------------------------------------------------------------------------
/src-tauri/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/64x64.png
--------------------------------------------------------------------------------
/src-tauri/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/icon.icns
--------------------------------------------------------------------------------
/src-tauri/src/assets/UI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/assets/UI.png
--------------------------------------------------------------------------------
/src-tauri/src/icons/32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/32x32.png
--------------------------------------------------------------------------------
/src-tauri/src/icons/64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/64x64.png
--------------------------------------------------------------------------------
/src-tauri/src/icons/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/icon.icns
--------------------------------------------------------------------------------
/src-tauri/src/icons/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/icon.ico
--------------------------------------------------------------------------------
/src-tauri/icons/128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/128x128@2x.png
--------------------------------------------------------------------------------
/src-tauri/icons/setupBanner.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/setupBanner.bmp
--------------------------------------------------------------------------------
/src-tauri/src/icons/128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/128x128.png
--------------------------------------------------------------------------------
/src-tauri/src/icons/512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/512x512.png
--------------------------------------------------------------------------------
/src-tauri/src/icons/128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/128x128@2x.png
--------------------------------------------------------------------------------
/src-tauri/icons/setupBackground.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/icons/setupBackground.bmp
--------------------------------------------------------------------------------
/src-tauri/src/icons/setupBanner.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/setupBanner.bmp
--------------------------------------------------------------------------------
/src-tauri/src/icons/setupBackground.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Blakeinstein/Bloop/HEAD/src-tauri/src/icons/setupBackground.bmp
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Added by cargo
2 |
3 | target
4 | node_modules
5 | cargo.lock
6 | bloop.code-workspace
7 |
8 | dist
9 | .cache
10 | .dnconfig
11 | WixTools
12 | keys
13 | *.log
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/base/_helpers.scss:
--------------------------------------------------------------------------------
1 | .selected {
2 | background-color: #333;
3 | }
4 |
5 | .hidden {
6 | display: none;
7 | }
8 |
9 | .shaded {
10 | opacity: 0.9;
11 | }
12 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 |
3 | export default defineConfig({
4 | root: 'src-tauri/app',
5 | build: {
6 | target: 'es2021',
7 | outDir: '../dist/',
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/main.scss:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | @import "base/base", "base/helpers";
4 |
5 | @import "components/titlebar", "components/spotlight", "components/icons",
6 | "components/editor", "components/window";
7 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/components/_window.scss:
--------------------------------------------------------------------------------
1 | .window-body {
2 | flex-grow: 1;
3 | width: 100%;
4 | order: 2;
5 | overflow-x: hidden;
6 | overflow-y: auto;
7 | backdrop-filter: blur(2px);
8 | background: transparent;
9 | cursor: text;
10 | }
11 |
--------------------------------------------------------------------------------
/src-tauri/app/js/components/action.ts:
--------------------------------------------------------------------------------
1 | class Action {
2 | name: string;
3 | tags: string[];
4 | desc: string;
5 | dom: HTMLElement;
6 |
7 | constructor(name: string, tags: string, desc: string, listItem: HTMLElement) {
8 | this.name = name;
9 | this.tags = tags.split(",");
10 | this.desc = desc;
11 | this.dom = listItem;
12 | }
13 | }
14 |
15 | export default Action;
16 |
--------------------------------------------------------------------------------
/src-tauri/rustfmt.toml:
--------------------------------------------------------------------------------
1 | max_width = 100
2 | hard_tabs = false
3 | tab_spaces = 2
4 | newline_style = "Auto"
5 | use_small_heuristics = "Default"
6 | reorder_imports = true
7 | reorder_modules = true
8 | remove_nested_parens = true
9 | edition = "2018"
10 | merge_derives = true
11 | use_try_shorthand = false
12 | use_field_init_shorthand = false
13 | force_explicit_abi = true
14 | imports_granularity = "Crate"
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bloop",
3 | "version": "0.4.8",
4 | "license": "MIT",
5 | "source": "src/web/index.html",
6 | "scripts": {
7 | "serve": "vite",
8 | "build": "vite build",
9 | "dev": "tauri dev",
10 | "release": "tauri build"
11 | },
12 | "dependencies": {
13 | "@tauri-apps/api": "1.0.0-beta.8",
14 | "ace-builds": "^1.4.12",
15 | "fuse.js": "^6.4.6"
16 | },
17 | "devDependencies": {
18 | "@tauri-apps/cli": "1.0.0-beta.10",
19 | "npm-run-all": "^4.1.5",
20 | "sass": "^1.38.0",
21 | "vite": "^2.5.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src-tauri/config/default.toml:
--------------------------------------------------------------------------------
1 | [global]
2 | custom_css = ""
3 | width = 900
4 | height = 400
5 | always_on_top = false
6 |
7 | [vars]
8 | font = '"SF mono", "Cascadia Code", "CascadiaCode Nerd Font", monaco, monospace'
9 | spotlight_font = '"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif'
10 | font_size = '30px'
11 | editor_font_size = '20px'
12 | gutter_size = '4.2rem'
13 | gutter_color = '#161616c2'
14 | editor_color = '#1f1f1fc2'
15 | gutter_text_color = '#999'
16 | editor_text_color = 'white'
17 | seperator_width = '1.2px'
18 | seperator_color = '#f0f0fe2'
19 | # syntax
20 | syntax_comment = '#888ea6'
21 | syntax_string = '#ff4c7c'
22 | syntax_attribute = '#4cffb2'
23 | syntax_number = '#ffb24c'
24 | syntax_extra = '#3586ff'
25 | syntax_keyword = '#32ff47'
--------------------------------------------------------------------------------
/src-tauri/src/config/default.toml:
--------------------------------------------------------------------------------
1 | [global]
2 | custom_css = ""
3 | width = 900
4 | height = 400
5 | always_on_top = false
6 |
7 | [vars]
8 | font = '"SF mono", "Cascadia Code", "CascadiaCode Nerd Font", monaco, monospace'
9 | spotlight_font = '"HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif'
10 | font_size = '30px'
11 | editor_font_size = '20px'
12 | gutter_size = '4.2rem'
13 | gutter_color = '#161616c2'
14 | editor_color = '#1f1f1fc2'
15 | gutter_text_color = '#999'
16 | editor_text_color = 'white'
17 | seperator_width = '1.2px'
18 | seperator_color = '#f0f0fe2'
19 | # syntax
20 | syntax_comment = '#888ea6'
21 | syntax_string = '#ff4c7c'
22 | syntax_attribute = '#4cffb2'
23 | syntax_number = '#ffb24c'
24 | syntax_extra = '#3586ff'
25 | syntax_keyword = '#32ff47'
--------------------------------------------------------------------------------
/src-tauri/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "bloop"
3 | version = "0.4.8"
4 | authors = [ "Blaine " ]
5 | edition = "2018"
6 | build = "build.rs"
7 | description = "A hackable scratchpad for developers"
8 |
9 | [build-dependencies]
10 | tauri-build = { version = "1.0.0-beta.4" }
11 |
12 | [features]
13 | default = [ "custom-protocol" ]
14 | custom-protocol = [ "tauri/custom-protocol" ]
15 |
16 | [dependencies]
17 | serde_json = "1.0.56"
18 | serde = { version = "1.0.114", features = [ "derive" ] }
19 | glob = "0.3.0"
20 | once_cell = "1.7.2"
21 | config = "0.11.0"
22 |
23 | [dependencies.tauri]
24 | version = "1.0.0-beta.8"
25 | features = ["fs-read-dir", "fs-read-text-file", "fs-write-file", "path-all", "shell-open", "window-all"]
26 |
27 | [profile.release]
28 | panic = "abort"
29 | codegen-units = 1
30 | lto = true
31 | incremental = false
32 | opt-level = "s"
33 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/base/_base.scss:
--------------------------------------------------------------------------------
1 | *,
2 | *:before,
3 | *:after {
4 | box-sizing: border-box;
5 | scrollbar-width: thin !important;
6 | scrollbar-color: var(--gutter_color) #afafaf52 !important;
7 | }
8 |
9 | * {
10 | &::-webkit-scrollbar {
11 | width: 8px;
12 | }
13 |
14 | &::-webkit-scrollbar-track {
15 | background: var(--gutter_color);
16 | }
17 |
18 | &::-webkit-scrollbar-thumb {
19 | background-color: #afafaf52;
20 | border-radius: 20px;
21 | border: 1px solid black;
22 | }
23 | }
24 |
25 | :root {
26 | font-family: var(--font);
27 | }
28 |
29 | html {
30 | height: 100%;
31 | }
32 |
33 | body {
34 | background-color: transparent;
35 | height: 100vh;
36 | width: 100vw;
37 | margin: 0px;
38 | cursor: default;
39 | }
40 |
41 | #content {
42 | height: 100%;
43 | width: 100%;
44 | display: flex;
45 | flex-direction: column;
46 | }
47 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/components/_editor.scss:
--------------------------------------------------------------------------------
1 | .editor-container {
2 | height: 100%;
3 | }
4 |
5 | .ace-tm {
6 | background-color: var(--editor_color);
7 | color: var(--editor_text_color);
8 | font-size: var(--editor_font_size);
9 |
10 | .ace_gutter {
11 | background: var(--gutter_color);
12 | color: var(--gutter_text_color);
13 | border-right: var(--seperator_width) solid var(--seperator_color);
14 | }
15 | .ace_gutter-active-line {
16 | background: initial;
17 | }
18 | .ace_cursor {
19 | color: white;
20 | }
21 | .ace_indent-guide {
22 | opacity: 0.05;
23 | }
24 | // syntax highlight
25 | .ace_comment {
26 | color: var(--syntax_comment);
27 | }
28 | .ace_string {
29 | color: var(--syntax_string);
30 | }
31 | .ace_attribute {
32 | color: var(--syntax_attribute);
33 | }
34 | .ace_number {
35 | color: var(--syntax_number);
36 | }
37 | .ace_extra {
38 | color: var(--syntax_extra);
39 | }
40 | .ace_keyword {
41 | color: var(--syntax_keyword);
42 | }
43 | }
44 |
45 | .ace_folding-enabled > .ace_gutter-cell {
46 | padding: none;
47 | }
48 |
--------------------------------------------------------------------------------
/src-tauri/scripts/owoifier.js:
--------------------------------------------------------------------------------
1 | /**
2 | {
3 | "api":1,
4 | "name":"OWOifier",
5 | "description":"OWOify!",
6 | "author":"Blaine",
7 | "icon":"color-wheel",
8 | "tags":"meme,text,joke,fun",
9 | "bias":0.0
10 | }
11 | **/
12 | const faces=["(・`ω´・)",";;w;;","owo","UwU",">w<","^w^"];
13 |
14 | function owoify(text)
15 | {
16 |
17 | let v = text;
18 |
19 | v = v.replace(/(?:r|l)/g, "w");
20 | v = v.replace(/(?:R|L)/g, "W");
21 | v = v.replace(/n([aeiou])/g, 'ny$1');
22 | v = v.replace(/N([aeiou])/g, 'Ny$1');
23 | v = v.replace(/N([AEIOU])/g, 'Ny$1');
24 | v = v.replace(/ove/g, "uv");
25 |
26 |
27 | let exclamationPointCount = 0;
28 | let i;
29 | let stringsearch = "!";
30 | //for loop counts the # of individual exclamation points
31 | for(let i=0; i < v.length; i++) {
32 | stringsearch===v[exclamationPointCount++]
33 | };
34 | for (i = 0; i < exclamationPointCount; i++) {
35 | v = v.replace("!", " "+ faces[Math.floor(Math.random()*faces.length)]+ " ");
36 | }
37 | return (v);
38 | }
39 |
40 | function main(state) {
41 | try {
42 | state.text = owoify(state.text);
43 | }
44 | catch(error) {
45 | state.postError("Explain what went wrong here...")
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/src-tauri/app/js/components/editor.ts:
--------------------------------------------------------------------------------
1 | import ace from "ace-builds";
2 | import "ace-builds/src-min-noconflict/keybinding-sublime";
3 | import "./bloopMode";
4 |
5 | const EditorElement: HTMLElement = document.querySelector(".editor-container");
6 |
7 | const Config: Record = {
8 | cursorStyle: "ace",
9 | fontFamily: `var(--font)`,
10 | fontSize: `var(--editor_font_size)`,
11 | useWorker: false,
12 | indentedSoftWrap: false,
13 | wrap: true,
14 | hScrollBarAlwaysVisible: false,
15 | vScrollBarAlwaysVisible: false,
16 | autoScrollEditorIntoView: true,
17 | showPrintMargin: false,
18 | };
19 |
20 | const editor = ace.edit(EditorElement);
21 | editor.setOptions(Config);
22 | editor.setKeyboardHandler("ace/keyboard/sublime");
23 | editor.session.setMode("ace/mode/bloop");
24 |
25 | editor.setValue(localStorage.getItem("bloopTextData") ?? "");
26 |
27 | window.addEventListener("drop", (e) => {
28 | e.preventDefault();
29 |
30 | for (let i in e.dataTransfer.files) {
31 | let reader = new FileReader();
32 | reader.onload = (ev) => {
33 | editor.setValue(ev.target.result as string);
34 | };
35 | reader.readAsText(e.dataTransfer.files[i]);
36 | }
37 | });
38 |
39 | window.addEventListener("dragover", (e) => {
40 | e.preventDefault();
41 | });
42 |
43 | export default editor;
44 |
--------------------------------------------------------------------------------
/src-tauri/app/js/components/titlebar.ts:
--------------------------------------------------------------------------------
1 | import { appWindow } from "@tauri-apps/api/window";
2 |
3 | class TitleBar {
4 | titlebar: HTMLElement;
5 | close: HTMLElement;
6 | minimize: HTMLElement;
7 | maximize: HTMLElement;
8 | fullscreenSvg: HTMLElement;
9 | maximizeSvg: HTMLElement;
10 | maximizeState: boolean;
11 |
12 | constructor() {
13 | this.close = document.querySelector(".titlebar-close");
14 | this.minimize = document.querySelector(".titlebar-minimize");
15 | this.maximize = document.querySelector(".titlebar-fullscreen");
16 | this.fullscreenSvg = document.querySelector(".fullscreen-svg");
17 | this.maximizeSvg = document.querySelector(".maximize-svg");
18 | this.titlebar = document.querySelector(".titlebar");
19 | this.maximizeState = false;
20 |
21 | this.init();
22 | }
23 |
24 | maximizeEvent() {
25 | this.maximizeState = !this.maximizeState;
26 | this.fullscreenSvg.classList.toggle("hidden");
27 | this.maximizeSvg.classList.toggle("hidden");
28 | this.maximizeState ? appWindow.unmaximize() : appWindow.maximize();
29 | }
30 |
31 | init() {
32 | this.close.onclick = (e) => {
33 | e.stopPropagation();
34 | appWindow.close();
35 | };
36 | this.minimize.onclick = (e) => {
37 | appWindow.minimize();
38 | e.stopPropagation();
39 | };
40 | this.maximize.onclick = (e) => this.maximizeEvent();
41 | this.titlebar.ondblclick = () => this.maximizeEvent();
42 | }
43 | }
44 |
45 | export default TitleBar;
46 |
--------------------------------------------------------------------------------
/src-tauri/app/js/components/settings.ts:
--------------------------------------------------------------------------------
1 | import { invoke } from "@tauri-apps/api/tauri";
2 | import { open } from "@tauri-apps/api/shell";
3 | import { configDir } from "@tauri-apps/api/path";
4 | class Settings {
5 | root: HTMLElement;
6 | settingsButton: HTMLElement;
7 | cssElement: HTMLStyleElement;
8 |
9 | constructor() {
10 | this.root = document.documentElement;
11 | this.cssElement = document.createElement("style") as HTMLStyleElement;
12 | document.head.append(this.cssElement);
13 | this.settingsButton = document.querySelector(".titlebar-settings");
14 | this.settingsButton.addEventListener("click", this.openSettingsFile);
15 | invoke("settings").then(
16 | (config) => this.updateConfig(config as string),
17 | (err) => console.log(err)
18 | );
19 | document.body.style.display = "initial";
20 | }
21 | updateConfig(config: string) {
22 | let settings: Record = JSON.parse(config);
23 | Object.entries(settings["vars"] as Record).forEach(
24 | ([prop, value]) => {
25 | this.root.style.setProperty("--" + prop, value);
26 | }
27 | );
28 | if (settings["global"]["custom_css"]) {
29 | invoke("custom_css").then(
30 | (css) => (this.cssElement.textContent = css as string),
31 | (err) => console.log(err)
32 | );
33 | }
34 | }
35 | openSettingsFile() {
36 | configDir()
37 | .then((dir) => open(dir + "bloop/config.toml"))
38 | .catch((err) => console.log(err));
39 | }
40 | }
41 |
42 | export default Settings;
43 |
--------------------------------------------------------------------------------
/src-tauri/app/js/app.ts:
--------------------------------------------------------------------------------
1 | import { invoke } from "@tauri-apps/api/tauri";
2 | import { appWindow, PhysicalSize, PhysicalPosition } from '@tauri-apps/api/window'
3 | import { Ace } from "ace-builds";
4 |
5 | import editor from "./components/editor";
6 | import Spotlight from "./components/spotlight";
7 | import EditorObj from "./components/editorObj";
8 | import TitleBar from "./components/titlebar";
9 | import Settings from "./components/settings";
10 |
11 | declare global {
12 | interface Window {
13 | editor: Ace.Editor;
14 | editorObj: EditorObj;
15 | titlebar: TitleBar;
16 | spotlight: Spotlight;
17 | settings: Settings;
18 | requireMod: Function;
19 | }
20 | }
21 | window.settings = new Settings();
22 |
23 | window.editor = editor;
24 |
25 | window.titlebar = new TitleBar();
26 |
27 | window.editorObj = new EditorObj(editor);
28 | // * Implement Spotlight
29 | window.spotlight = new Spotlight(window.editorObj, editor);
30 |
31 | window.requireMod = async (path: string) => {
32 | if (!path.endsWith(".js")) path += ".js";
33 | try {
34 | const code = await invoke("require", { scriptName: path });
35 | const func = new Function(
36 | `let exports = {}; const module = { exports }; ${code}; return module.exports;`
37 | );
38 | return func();
39 | } catch (err) {
40 | window.editorObj.postError(err);
41 | }
42 | };
43 |
44 | window.onload = () => {
45 | invoke("doc_ready");
46 | window.editorObj.focus();
47 | };
48 |
49 | setInterval( async () => {
50 | localStorage.setItem("bloopTextData", window.editor.getValue());
51 | }, 5000);
--------------------------------------------------------------------------------
/src-tauri/app/js/components/editorObj.ts:
--------------------------------------------------------------------------------
1 | import { invoke } from "@tauri-apps/api/tauri";
2 | import { Ace } from "ace-builds";
3 | import Spotlight from "./spotlight";
4 |
5 | class EditorObj {
6 | _script: String;
7 | editor: Ace.Editor;
8 | spotlight: Spotlight;
9 |
10 | constructor(editor: Ace.Editor) {
11 | this.editor = editor;
12 | }
13 |
14 | get script() {
15 | return this._script;
16 | }
17 | get isSelection() {
18 | return !this.editor.getSelection().isEmpty();
19 | }
20 | get fullText() {
21 | return this.editor.getValue();
22 | }
23 | get text() {
24 | return this.isSelection ? this.selection : this.fullText;
25 | }
26 | get selection() {
27 | return this.editor.getSelectedText();
28 | }
29 |
30 | set script(value) {
31 | this._script = value;
32 | invoke("exec", { scriptName: value }).catch((error) =>
33 | this.postError(error)
34 | );
35 | }
36 | set selection(value) {
37 | let range = this.editor.getSelection().getRange();
38 | this.editor.session.replace(range, value);
39 | }
40 | set fullText(value) {
41 | this.editor.setValue(value);
42 | this.editor.clearSelection();
43 | }
44 | set text(value) {
45 | if (this.isSelection) this.selection = value;
46 | else this.fullText = value;
47 | }
48 |
49 | focus() {
50 | this.editor.focus();
51 | this.editor.navigateFileEnd();
52 | }
53 |
54 | postMessage(message) {
55 | this.spotlight.labelText[1].innerText = message;
56 | this.spotlight.labelText[0].classList.add("labelHidden");
57 | this.spotlight.labelText[1].classList.remove("labelHidden");
58 | }
59 |
60 | postInfo(message) {
61 | this.postMessage(message);
62 | this.spotlight.label.classList.add("postInfo");
63 | }
64 |
65 | postError(message) {
66 | this.postMessage(message);
67 | this.spotlight.labelText[1].classList.remove("labelHidden");
68 | this.spotlight.label.classList.add("postError");
69 | }
70 | }
71 |
72 | export default EditorObj;
73 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: Release
4 |
5 | # Controls when the action will run. Triggers the workflow on push or pull request
6 | # events but only for the master branch
7 | on:
8 | workflow_dispatch:
9 | push:
10 | branches: [Release]
11 |
12 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
13 | jobs:
14 | # This workflow contains a single job called "build"
15 | build:
16 | strategy:
17 | fail-fast: false
18 | matrix:
19 | platform: [macos-latest, ubuntu-latest, windows-latest]
20 |
21 | runs-on: ${{ matrix.platform }}
22 | steps:
23 | # Set up core dependencies
24 | - uses: actions/checkout@v2
25 | - name: setup node
26 | uses: actions/setup-node@v1
27 | with:
28 | node-version: 14
29 | - name: install Rust stable
30 | uses: actions-rs/toolchain@v1
31 | with:
32 | toolchain: stable
33 | - name: install webkit2gtk (ubuntu only)
34 | if: matrix.platform == 'ubuntu-latest'
35 | run: |
36 | sudo apt-get update
37 | sudo apt-get install -y webkit2gtk-4.0
38 |
39 | # Get Boop scripts
40 | - name: Get Boop scripts
41 | run: |
42 | git clone http://github.com/ivanmathy/boop
43 | mv boop/Boop/Boop/scripts/* src-tauri/scripts/
44 |
45 | # Build web component
46 | - name: install app dependencies and build it
47 | run: yarn
48 |
49 | # Create release
50 | - uses: tauri-apps/tauri-action@v0
51 | env:
52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53 | TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
54 | TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
55 | with:
56 | tagName: v__VERSION__ # the action automatically replaces \_\_VERSION\_\_ with the app version
57 | releaseName: "Release v__VERSION__"
58 | releaseBody: "Release v__VERSION__."
59 | draft: true
60 | prerelease: false
61 |
--------------------------------------------------------------------------------
/src-tauri/src/settings.rs:
--------------------------------------------------------------------------------
1 | use std::collections::HashMap;
2 | use std::error::Error;
3 | use std::fs::{create_dir_all, read_to_string, File as FileWriter};
4 | use std::io::Write;
5 |
6 | use config::{Config, File, FileFormat};
7 | use serde::{Deserialize, Serialize};
8 | use tauri::api::dialog::message;
9 | use tauri::api::path::config_dir;
10 |
11 | #[derive(Debug, Serialize, Deserialize)]
12 | pub struct Global {
13 | pub custom_css: String,
14 | pub width: u32,
15 | pub height: u32,
16 | pub always_on_top: bool,
17 | }
18 |
19 | #[derive(Debug, Serialize, Deserialize)]
20 | pub struct BloopConfig {
21 | pub global: Global,
22 | pub vars: HashMap,
23 | }
24 |
25 | impl BloopConfig {
26 | pub fn new() -> Result> {
27 | let mut settings = Config::default();
28 | const DEFAULT_CONFIG: &'static str = include_str!("../config/default.toml");
29 | if let Err(err) = settings.merge(File::from_str(DEFAULT_CONFIG, FileFormat::Toml)) {
30 | message(Option::<&tauri::Window>::None, "Error parsing default config", err.to_string());
31 | }
32 | if let Some(config_path) = config_dir() {
33 | let config_dir = config_path.join("bloop");
34 | let bloop_config = config_dir.join("config.toml");
35 | if config_dir.exists() && bloop_config.exists() {
36 | if let Err(err) = settings.merge(File::from(bloop_config)) {
37 | message(Option::<&tauri::Window>::None, "Error parsing config", err.to_string());
38 | }
39 | } else {
40 | create_dir_all(config_dir)?;
41 | let mut file = FileWriter::create(bloop_config)?;
42 | file.write_all(DEFAULT_CONFIG.as_bytes())?;
43 | }
44 | }
45 | settings.try_into().map_err(|err| err.into())
46 | }
47 | }
48 |
49 | pub fn custom_css(css_file_name: String) -> Option {
50 | if let Some(config_path) = config_dir() {
51 | let css_file = config_path
52 | .join("bloop/themes")
53 | .join(css_file_name + ".css");
54 | if css_file.exists() {
55 | return Some(read_to_string(&css_file).unwrap());
56 | }
57 | }
58 | None
59 | }
60 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/components/_spotlight.scss:
--------------------------------------------------------------------------------
1 | #spotlight-wrapper {
2 | position: absolute;
3 | top: 15%;
4 | left: 0;
5 | right: 0;
6 | margin: 0 auto;
7 | width: 628px;
8 | }
9 |
10 | #spotlight {
11 | display: block;
12 | width: 100%;
13 | height: 56px;
14 | margin: auto;
15 |
16 | border-radius: 5px;
17 | -moz-border-radius: 5px;
18 | -webkit-border-radius: 5px;
19 | border-top-left-radius: 5px;
20 | border-top-right-radius: 5px;
21 |
22 | -moz-appearance: none;
23 | -webkit-appearance: none;
24 |
25 | -moz-box-shadow: 0 25px 60px 10px rgba(0, 0, 0, 0.3);
26 | -webkit-box-shadow: 0 25px 60px 10px rgba(0, 0, 0, 0.3);
27 | box-shadow: 0 25px 60px 10px rgba(0, 0, 0, 0.3);
28 |
29 | border: 1px solid rgba(0, 0, 0, 0.2);
30 | outline: none;
31 | font-size: 1.3rem;
32 | font-family: var(--spotlight_font);
33 | color: white;
34 | background-color: rgb(15, 15, 15);
35 | padding: 0 12px;
36 |
37 | &::placeholder {
38 | color: white;
39 | }
40 | }
41 | #action-list-placeholder {
42 | > div {
43 | grid-template-columns: auto;
44 | }
45 | }
46 |
47 | .action-list {
48 | display: flex;
49 | flex-flow: column;
50 | width: 100%;
51 | outline: none;
52 | font-size: 1.3rem;
53 | color: white;
54 | background-color: #0f0f0f;
55 | padding: 0 12px;
56 | margin: auto;
57 | list-style: none;
58 | max-height: 60vh;
59 |
60 | border-bottom-left-radius: 5px;
61 | border-bottom-right-radius: 5px;
62 |
63 | -moz-appearance: none;
64 | -webkit-appearance: none;
65 |
66 | box-shadow: 0 25px 60px 10px rgba(0, 0, 0, 0.3);
67 |
68 | overflow-x: hidden;
69 |
70 | li {
71 | width: 100%;
72 | height: 56px;
73 | padding: 0 12px;
74 | margin: auto 0;
75 |
76 | > div {
77 | height: 50px;
78 | grid-template-columns: 50px auto;
79 | gap: 5px;
80 | }
81 | }
82 | div {
83 | display: grid;
84 | align-items: center;
85 | gap: 4px;
86 | }
87 | }
88 |
89 | name {
90 | display: block;
91 | font-family: var(--spotlight_font);
92 | font-size: 1em;
93 | color: #dadada;
94 | }
95 |
96 | description {
97 | font-family: var(--spotlight_font);
98 | display: block;
99 | font-size: 0.7em;
100 | color: #606060;
101 | text-overflow: ellipsis;
102 | overflow: hidden;
103 | white-space: nowrap;
104 | }
105 |
--------------------------------------------------------------------------------
/src-tauri/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Bloop
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Press Ctrl +B to get started
36 |
37 |
Select your action
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
52 |
53 |
--------------------------------------------------------------------------------
/src-tauri/tauri.conf.json:
--------------------------------------------------------------------------------
1 | {
2 | "package": {
3 | "productName": "Bloop",
4 | "version": "0.4.8"
5 | },
6 | "build": {
7 | "distDir": "dist",
8 | "devPath": "http://localhost:3000",
9 | "beforeDevCommand": "yarn serve",
10 | "beforeBuildCommand": "yarn build"
11 | },
12 | "tauri": {
13 | "bundle": {
14 | "active": true,
15 | "targets": "all",
16 | "identifier": "Blaine",
17 | "icon": [
18 | "icons/32x32.png",
19 | "icons/128x128.png",
20 | "icons/128x128@2x.png",
21 | "icons/icon.icns",
22 | "icons/icon.ico"
23 | ],
24 | "resources": ["./scripts", "./config/default.toml"],
25 | "externalBin": [],
26 | "copyright": "Blaine",
27 | "category": "DeveloperTool",
28 | "shortDescription": "A hackable scratchpad for developers!",
29 | "longDescription": "A hackable scratchpad for developers!",
30 | "deb": {
31 | "depends": [],
32 | "useBootstrapper": false
33 | },
34 | "macOS": {
35 | "frameworks": [],
36 | "minimumSystemVersion": "",
37 | "useBootstrapper": false,
38 | "exceptionDomain": "",
39 | "signingIdentity": null,
40 | "entitlements": null
41 | },
42 | "windows": {
43 | "certificateThumbprint": null,
44 | "digestAlgorithm": "sha256",
45 | "timestampUrl": "",
46 | "wix": {
47 | "dialogImagePath": "icons/setupBackground.bmp",
48 | "bannerPath": "icons/setupBanner.bmp"
49 | }
50 | }
51 | },
52 | "updater": {
53 | "active": false,
54 | "endpoints": [
55 | "https://bloop-updates.azurewebsites.net/api/{{target}}/{{current_version}}"
56 | ],
57 | "dialog": false,
58 | "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ4Q0RGQzI4QUFBOTJCMwpSV1N6a3FxS3d0K01CTC9nck1WSVcwczhha3NyZ3dER2hsNFN6WDluandDdXlrOGNoc1hrNjhmVgo="
59 | },
60 | "allowlist": {
61 | "all": false,
62 | "window": {
63 | "all": true
64 | },
65 | "fs": {
66 | "all": false,
67 | "readTextFile": true,
68 | "writeFile": true,
69 | "readDir": true
70 | },
71 | "shell": {
72 | "all": false,
73 | "open": true
74 | },
75 | "path": {
76 | "all": true
77 | }
78 | },
79 | "windows": [
80 | {
81 | "title": "Bloop",
82 | "resizable": true,
83 | "fullscreen": false,
84 | "decorations": false,
85 | "transparent": true,
86 | "focus": true,
87 | "center": true,
88 | "fileDropEnabled": false
89 | }
90 | ],
91 | "security": {
92 | "csp": "default-src blob: data: filesystem: ws: http: https: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src-tauri/app/stylesheets/components/_titlebar.scss:
--------------------------------------------------------------------------------
1 | .titlebar {
2 | padding: 0;
3 | background-color: #3a3a3af6;
4 | border-top-left-radius: 2px;
5 | border-top-right-radius: 2px;
6 | width: 100%;
7 | height: 28px;
8 | z-index: 10;
9 | order: 1;
10 | user-select: none;
11 | flex-shrink: 0;
12 | display: flex;
13 | align-items: center;
14 | }
15 |
16 | .titlebar-stoplight {
17 | cursor: default;
18 | display: inline-grid;
19 | grid-template-columns: 1fr 1fr 1fr;
20 | place-items: center;
21 | position: absolute;
22 | width: 70px;
23 | float: left;
24 | }
25 |
26 | .titlebar:after,
27 | .titlebar-stoplight:after {
28 | content: " ";
29 | display: table;
30 | clear: both;
31 | }
32 |
33 | .titlebar-stoplight:hover svg {
34 | opacity: 1;
35 | }
36 |
37 | .titlebar-close,
38 | .titlebar-minimize,
39 | .titlebar-fullscreen {
40 | border-radius: 50%;
41 | line-height: 0;
42 | padding: 2px;
43 | }
44 |
45 | .titlebar svg {
46 | width: 8px;
47 | height: 8px;
48 | margin: auto;
49 | opacity: 0;
50 | }
51 |
52 | .titlebar-close {
53 | border: 1px solid #e2463f;
54 | background-color: #ff5f57;
55 | }
56 |
57 | .titlebar-close:active {
58 | border-color: #ad3934;
59 | background-color: #bf4943;
60 | }
61 |
62 | .titlebar-minimize {
63 | border: 1px solid #e1a116;
64 | background-color: #ffbd2e;
65 | }
66 |
67 | .titlebar-minimize:active {
68 | border-color: #ad7d15;
69 | background-color: #bf9123;
70 | }
71 |
72 | .titlebar-fullscreen,
73 | .titlebar-maximize {
74 | border: 1px solid #12ac28;
75 | background-color: #28c940;
76 | }
77 |
78 | .titlebar-fullscreen:active {
79 | border-color: #128622;
80 | background-color: #1f9a31;
81 | }
82 |
83 | .titlebar-spotlight {
84 | background: #1e1e1e;
85 | color: #e0e0e0;
86 | border-radius: 5px;
87 | height: 70%;
88 | width: 30%;
89 | margin: 0 auto;
90 | text-align: center;
91 | display: inline-grid;
92 | place-items: center;
93 | grid-template-areas: "label";
94 | grid-template-rows: 100%;
95 | }
96 |
97 | .titlebar-spotlight .label {
98 | font-size: 10px;
99 | width: 30%;
100 | transition: visibility 0s, opacity 0.4s ease-in-out;
101 | visibility: visible;
102 | position: absolute;
103 | z-index: 10;
104 | margin: 5px;
105 | text-overflow: clip;
106 | overflow: hidden;
107 | white-space: nowrap;
108 | grid-area: label;
109 | }
110 |
111 | .titlebar-settings {
112 | float: right;
113 | display: grid;
114 | margin-right: 0.2em;
115 |
116 | img {
117 | opacity: 0.4;
118 | transition: all 0.5s ease-in-out;
119 |
120 | &:hover {
121 | filter: invert(0.4);
122 | opacity: 0.7;
123 | }
124 | }
125 |
126 | &:hover {
127 | cursor: pointer;
128 | }
129 | }
130 |
131 | .postInfo {
132 | background-color: #3586ff;
133 | color: #dadada;
134 | }
135 |
136 | .postError {
137 | background-color: #ff4c7c;
138 | color: #dadada;
139 | }
140 |
141 | .labelHidden {
142 | visibility: hidden;
143 | opacity: 0;
144 | }
145 |
--------------------------------------------------------------------------------
/src-tauri/src/main.rs:
--------------------------------------------------------------------------------
1 | #![cfg_attr(
2 | all(not(debug_assertions), target_os = "windows"),
3 | windows_subsystem = "windows"
4 | )]
5 | mod scripts;
6 | mod settings;
7 |
8 | extern crate config;
9 | extern crate serde;
10 |
11 | use once_cell::sync::OnceCell;
12 | use std::collections::HashMap;
13 | use std::sync::{Arc, Mutex};
14 | use tauri::Manager;
15 |
16 | pub static PACKAGE_INFO: OnceCell = OnceCell::new();
17 | pub static GLOBAL_CONFIG: OnceCell = OnceCell::new();
18 |
19 | #[derive(Default)]
20 | struct Scripts(Arc>>);
21 |
22 | #[tauri::command]
23 | fn doc_ready(window: tauri::Window, scripts: tauri::State) -> Result {
24 | match scripts::build_scripts(window, &mut scripts.0.lock().unwrap()) {
25 | Ok(_) => Ok("".to_string()),
26 | Err(err) => Err(err.to_string()),
27 | }
28 | }
29 |
30 | #[tauri::command]
31 | fn exec(
32 | window: tauri::Window,
33 | scripts: tauri::State,
34 | script_name: String,
35 | ) -> Result {
36 | match scripts::script_eval(
37 | scripts
38 | .0
39 | .lock()
40 | .unwrap()
41 | .get(&script_name)
42 | .ok_or(format!("Script, {}, not found", &script_name))?,
43 | &window,
44 | ) {
45 | Ok(_) => Ok("".to_string()),
46 | Err(err) => Err(err.to_string()),
47 | }
48 | }
49 |
50 | #[tauri::command]
51 | fn require(scripts: tauri::State, script_name: String) -> Result {
52 | match scripts.0.lock().unwrap().get(&script_name) {
53 | Some(script) => Ok(script.string.clone()),
54 | None => Err("lib not found".into()),
55 | }
56 | }
57 |
58 | #[tauri::command]
59 | fn settings() -> Result {
60 | let config = GLOBAL_CONFIG.get().ok_or("Error reading config")?;
61 | serde_json::to_string(config).map_err(|err| err.to_string())
62 | }
63 |
64 | #[tauri::command]
65 | fn custom_css() -> String {
66 | let config = GLOBAL_CONFIG.get().unwrap();
67 | settings::custom_css(config.global.custom_css.clone()).unwrap_or_default()
68 | }
69 |
70 | fn main() {
71 | let context = tauri::generate_context!();
72 | PACKAGE_INFO.set(context.package_info().clone()).unwrap();
73 | let app_config = settings::BloopConfig::new().unwrap();
74 | const MIN_SIZE: tauri::Size = tauri::Size::Physical(tauri::PhysicalSize {
75 | width: 900,
76 | height: 400,
77 | });
78 | let width = app_config.global.width;
79 | let height = app_config.global.height;
80 | let always_on_top = app_config.global.always_on_top;
81 | GLOBAL_CONFIG.set(app_config).unwrap();
82 |
83 | tauri::Builder::default()
84 | .setup(move |app| {
85 | let window = app.get_window("main").unwrap();
86 | window.set_min_size(Some(MIN_SIZE)).unwrap();
87 | window
88 | .set_size(tauri::Size::Physical(tauri::PhysicalSize { width, height }))
89 | .unwrap();
90 | window
91 | .set_always_on_top(always_on_top)
92 | .unwrap();
93 | Ok(())
94 | })
95 | .manage(Scripts(Default::default()))
96 | .invoke_handler(tauri::generate_handler![
97 | doc_ready, exec, require, settings, custom_css
98 | ])
99 | .run(context)
100 | .expect("error while running tauri application");
101 | }
102 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
BLOOP
4 | A light weight hackable scratch pad for developers inspired from boop.
5 | Run scripts (written in JS) directly over any piece of text!
6 | Base64? EZ. Got an unreadable JSON? parse it! Just want to count characters? Well we got you covered.
7 | Or just use it to take notes, data persists in local storage :)
8 | The tool aims to be an exact imitation of boop built using web technologies and powered by Tauri .
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Inspired from Boop • Documentation • Find more scripts
21 |
22 |
23 |
24 | ### Documentation
25 | New? Read how to use bloop [here](https://github.com/Blakeinstein/Bloop/wiki/Getting-Started)
26 | #### Suggestions
27 | To add custom scripts add the scripts to your documents directory which you can confirm [here](https://docs.rs/dirs-next/2.0.0/dirs_next/fn.document_dir.html)
28 |
29 | Bloop supports ligaturized fonts, Some fonts are set up by default, but require you to install them manually. You can also use your own fonts, by changing `config.toml`. Suggested fonts =>
30 | * [SF Mono ligaturized](https://github.com/kube/sf-mono-ligaturized/tree/master/ligaturized)
31 | * [Cascadia Code](https://github.com/microsoft/cascadia-code)
32 |
33 |
34 | ### How to get Bloop
35 | You can obtain installer/binaries for your platform [here](https://github.com/Blakeinstein/Bloop/releases).
36 |
37 | ---
38 | Alternatively you can compile it yourself.
39 |
40 | > Only for developers.
41 |
42 | ### How to build from source
43 |
44 | - #### Config
45 | - ##### Setup Tauri and Yarn
46 | - Follow the setup guide from their [docs](https://tauri.studio/en/docs/getting-started/intro)
47 | - ##### Get Boop scripts
48 | - Get the base scripts from boop
49 | ```bash
50 | mkdir src-tauri
51 | git clone http://github.com/ivanmathy/boop
52 | mv boop/Boop/Boop/scripts src-tauri/
53 | ```
54 | - ##### Build web component
55 | - Install app dependencies and build it
56 | ```bash
57 | yarn && yarn build
58 | ```
59 | - ##### Copy data over to replicate tauri config
60 | ```bash
61 | mv dist src-tauri/
62 | mv src src-tauri/
63 | mv config src-tauri/
64 | mv icons src-tauri/
65 | mv ./Cargo.toml src-tauri/
66 | mv ./tauri.conf.json src-tauri/
67 | mv ./build.rs src-tauri/
68 | ```
69 | - #### Build
70 | - To build release binaries, use ``` yarn release ```, The resultant binaries would be located in ```src-tauri/target/release```
71 |
72 |
73 |
75 |
--------------------------------------------------------------------------------
/src-tauri/src/scripts.rs:
--------------------------------------------------------------------------------
1 | use glob::{glob, GlobError};
2 | use serde::{Deserialize, Serialize};
3 | use std::collections::HashMap;
4 | use std::fs::{create_dir_all, read_to_string};
5 | use std::path::PathBuf;
6 | use tauri::api::path::{document_dir, resource_dir};
7 | use tauri::Window;
8 |
9 | #[derive(Serialize, Deserialize)]
10 | struct Metadata {
11 | api: i16,
12 | name: String,
13 | description: String,
14 | author: String,
15 | icon: String,
16 | tags: String,
17 | }
18 |
19 | pub struct Script {
20 | metadata: Metadata,
21 | pub string: String,
22 | }
23 |
24 | impl Script {
25 | fn new(string: &str) -> Result