From d58ec2f9cf1624b4e217995173da4827b5adf1b3 Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Mon, 10 Aug 2026 21:07:39 +0200 Subject: [PATCH 1/7] move client to webapp --- CONTRIBUTING.md | 10 ++++ ROADMAP.md | 4 +- package-lock.json | 51 ++++++++++++++++-- package.json | 2 +- torii-client/README.md | 25 +-------- torii-client/{ => webapp}/.browserslistrc | 0 torii-client/{ => webapp}/.eslintrc.js | 0 torii-client/{ => webapp}/.gitignore | 0 torii-client/{ => webapp}/.prettierrc | 0 torii-client/webapp/README.md | 24 +++++++++ torii-client/{ => webapp}/index.html | 0 torii-client/{ => webapp}/package.json | 2 +- torii-client/{ => webapp}/public/favicon.ico | Bin torii-client/{ => webapp}/public/index.html | 0 torii-client/{ => webapp}/src/App.vue | 0 torii-client/{ => webapp}/src/assets/logo.png | Bin .../src/components/LanguageSelect.vue | 0 .../src/components/article/MarkdownEditor.vue | 0 .../article/MarkdownEditorAutocomplete.vue | 0 .../article/autocomplete-extension.ts | 0 .../src/components/image/ImageEditor.vue | 0 .../src/composables/recentProjects.ts | 0 .../src/composables/settings-window.ts | 0 .../src/composables/watch-locale.ts | 0 torii-client/{ => webapp}/src/locales/en.json | 0 torii-client/{ => webapp}/src/locales/jp.json | 0 torii-client/{ => webapp}/src/locales/zh.json | 0 torii-client/{ => webapp}/src/main.ts | 0 torii-client/{ => webapp}/src/router/index.ts | 0 torii-client/{ => webapp}/src/shims-vue.d.ts | 0 .../{ => webapp}/src/stores/settings.ts | 0 .../{ => webapp}/src/styles/global.scss | 0 torii-client/{ => webapp}/src/types.d.ts | 0 .../{ => webapp}/src/ui/UIDropRegion.vue | 0 .../{ => webapp}/src/ui/UIFileTree.vue | 0 torii-client/{ => webapp}/src/ui/UISelect.vue | 0 .../{ => webapp}/src/ui/UISpanInput.vue | 0 torii-client/{ => webapp}/src/ui/UITree.vue | 0 .../{ => webapp}/src/views/AboutView.vue | 0 .../{ => webapp}/src/views/HomeView.vue | 0 .../src/views/RecentProjectsView.vue | 0 .../src/views/project/ProjectView.vue | 0 .../views/settings/GeneralSettingsView.vue | 0 .../src/views/settings/SettingsView.vue | 0 .../src/views/settings/ThemeSettingsView.vue | 0 torii-client/{ => webapp}/tsconfig.json | 4 +- torii-client/{ => webapp}/typedoc.json | 0 torii-client/{ => webapp}/vite.config.ts | 0 torii-workspaces/welcome/Changelog.md | 6 ++- 49 files changed, 93 insertions(+), 35 deletions(-) rename torii-client/{ => webapp}/.browserslistrc (100%) rename torii-client/{ => webapp}/.eslintrc.js (100%) rename torii-client/{ => webapp}/.gitignore (100%) rename torii-client/{ => webapp}/.prettierrc (100%) create mode 100644 torii-client/webapp/README.md rename torii-client/{ => webapp}/index.html (100%) rename torii-client/{ => webapp}/package.json (98%) rename torii-client/{ => webapp}/public/favicon.ico (100%) rename torii-client/{ => webapp}/public/index.html (100%) rename torii-client/{ => webapp}/src/App.vue (100%) rename torii-client/{ => webapp}/src/assets/logo.png (100%) rename torii-client/{ => webapp}/src/components/LanguageSelect.vue (100%) rename torii-client/{ => webapp}/src/components/article/MarkdownEditor.vue (100%) rename torii-client/{ => webapp}/src/components/article/MarkdownEditorAutocomplete.vue (100%) rename torii-client/{ => webapp}/src/components/article/autocomplete-extension.ts (100%) rename torii-client/{ => webapp}/src/components/image/ImageEditor.vue (100%) rename torii-client/{ => webapp}/src/composables/recentProjects.ts (100%) rename torii-client/{ => webapp}/src/composables/settings-window.ts (100%) rename torii-client/{ => webapp}/src/composables/watch-locale.ts (100%) rename torii-client/{ => webapp}/src/locales/en.json (100%) rename torii-client/{ => webapp}/src/locales/jp.json (100%) rename torii-client/{ => webapp}/src/locales/zh.json (100%) rename torii-client/{ => webapp}/src/main.ts (100%) rename torii-client/{ => webapp}/src/router/index.ts (100%) rename torii-client/{ => webapp}/src/shims-vue.d.ts (100%) rename torii-client/{ => webapp}/src/stores/settings.ts (100%) rename torii-client/{ => webapp}/src/styles/global.scss (100%) rename torii-client/{ => webapp}/src/types.d.ts (100%) rename torii-client/{ => webapp}/src/ui/UIDropRegion.vue (100%) rename torii-client/{ => webapp}/src/ui/UIFileTree.vue (100%) rename torii-client/{ => webapp}/src/ui/UISelect.vue (100%) rename torii-client/{ => webapp}/src/ui/UISpanInput.vue (100%) rename torii-client/{ => webapp}/src/ui/UITree.vue (100%) rename torii-client/{ => webapp}/src/views/AboutView.vue (100%) rename torii-client/{ => webapp}/src/views/HomeView.vue (100%) rename torii-client/{ => webapp}/src/views/RecentProjectsView.vue (100%) rename torii-client/{ => webapp}/src/views/project/ProjectView.vue (100%) rename torii-client/{ => webapp}/src/views/settings/GeneralSettingsView.vue (100%) rename torii-client/{ => webapp}/src/views/settings/SettingsView.vue (100%) rename torii-client/{ => webapp}/src/views/settings/ThemeSettingsView.vue (100%) rename torii-client/{ => webapp}/tsconfig.json (85%) rename torii-client/{ => webapp}/typedoc.json (100%) rename torii-client/{ => webapp}/vite.config.ts (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ee67ea6..0d010e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,9 @@ Since all contributors would need to start the application anyway, an exhaustive contributors guide is provided in-app after starting in development mode. +If you are serious about contributing to this repository, you can find a quick way to start the application in development mode below. Please be aware of the [Pull Request Rules](#pull-request-rules). Breaking these rules will result in reactions such as your Pull Request to be rejected or your account restricted in this repository. + +### Quickstart + This contributors guide is short and will only help you run a minimal working Torii app. First make sure you have the [Rust Programming Language](https://rust-lang.org/) (which comes with [cargo](https://doc.rust-lang.org/cargo/)) and [NodeJS](https://nodejs.org/en) (which comes with [npm](https://docs.npmjs.com/cli/v11/commands/npm) and [npx](https://docs.npmjs.com/cli/v11/commands/npx)) installed. This guide assumes you have some prior familiarity with these tools. First, install all client dependencies with the following command. You will have to run this command everytime when client dependencies change (e.g. after pulling from remote). This will generate the `node_modules` directory, which contains all client dependencies. @@ -22,3 +26,9 @@ Now you should see the application winow which comes with at least two default w cd torii-api go run src/main.go serve ``` --> + +### Pull Request Rules + +- **No vibes.** You are allowed to use smart, contextless autocompletion but code which has been subject to agent generation is not allowed in this repository. + +- **English Codebase.** We allow to interact with this repositories issuesses and discussions in different languages. However excluded are all commit messages, source code and the title and first message in a Pull Request, which have to be in English. diff --git a/ROADMAP.md b/ROADMAP.md index 6e008b7..ce5d32e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -89,6 +89,9 @@ The first stage of the project is to create a simple file browser like applicati ### `v0.0.0-dev9` [NEXT] +- [ ] Client Refactoring (vue app and plugins first steps) + - [ ] Plugin: A separate non-app code module. + - [ ] Views: A panel which can be defined by a module. - [x] Client Documentation (Typedoc Infrastructure) - [ ] Breadcrumb Header - [x] Expand Footer with Edit and View mode. @@ -107,7 +110,6 @@ The first stage of the project is to create a simple file browser like applicati ### `v0.0.0-dev10` -- [ ] Client Refactoring (vue app and plugins first steps) - [ ] Client Documentation (Github CI) - [ ] [clean-jsdoc-theme](https://www.npmjs.com/package/@clean-jsdoc-theme/typedoc) - [ ] Remove Naive UI dependency and implement custom vue components diff --git a/package-lock.json b/package-lock.json index f8f3f83..590648f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "Torii", "workspaces": [ - "torii-client" + "torii-client/**" ], "devDependencies": { "@tauri-apps/cli": "^2.11.1", @@ -1484,6 +1484,10 @@ "vue": "^3.0.0" } }, + "node_modules/@torii/webapp": { + "resolved": "torii-client/webapp", + "link": true + }, "node_modules/@types/body-parser": { "version": "1.19.6", "dev": true, @@ -10024,10 +10028,6 @@ "node": ">=0.6" } }, - "node_modules/torii-client": { - "resolved": "torii-client", - "link": true - }, "node_modules/totalist": { "version": "3.0.1", "dev": true, @@ -11580,6 +11580,47 @@ "peerDependencies": { "vue": "^3.2.0" } + }, + "torii-client/webapp": { + "name": "@torii/webapp", + "version": "0.1.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0", + "@tauri-apps/plugin-dialog": "^2.7.1", + "@tauri-apps/plugin-opener": "^2.5.4", + "@tauri-apps/plugin-store": "^2.4.3", + "@tiptap/extension-list": "^3.27.1", + "@tiptap/markdown": "^3.27.1", + "@tiptap/pm": "^3.27.1", + "@tiptap/starter-kit": "^3.27.1", + "@tiptap/vue-3": "^3.27.1", + "pinia": "^3.0.4", + "typedoc": "^0.28.20", + "typedoc-plugin-vue": "^1.5.1", + "vue": "^3.2.13", + "vue-i18n": "^11.4.5", + "vue-router": "~4.0.3" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^5.4.0", + "@typescript-eslint/parser": "^5.4.0", + "@vicons/ionicons5": "^0.13.0", + "@vicons/utils": "^0.1.4", + "@vue/cli-plugin-eslint": "^5.0.9", + "@vue/cli-plugin-router": "~5.0.0", + "@vue/cli-plugin-typescript": "^5.0.9", + "@vue/cli-service": "~5.0.0", + "@vue/eslint-config-typescript": "^9.1.0", + "eslint": "^7.32.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-vue": "^8.0.3", + "naive-ui": "^2.44.1", + "prettier": "^2.4.1", + "sass": "^1.101.0", + "sass-loader": "^17.0.0", + "typescript": "~4.5.5" + } } } } diff --git a/package.json b/package.json index 1da485e..7ad38e3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "Torii", "type": "module", "workspaces": [ - "torii-client" + "torii-client/**" ], "devDependencies": { "@tauri-apps/cli": "^2.11.1", diff --git a/torii-client/README.md b/torii-client/README.md index ed94801..bf1ee7e 100644 --- a/torii-client/README.md +++ b/torii-client/README.md @@ -1,24 +1,3 @@ -# torii-client +# Torii Client Infrastructure -## Project setup -``` -npm install -``` - -### Compiles and hot-reloads for development -``` -npm run serve -``` - -### Compiles and minifies for production -``` -npm run build -``` - -### Lints and fixes files -``` -npm run lint -``` - -### Customize configuration -See [Configuration Reference](https://cli.vuejs.org/config/). +- [webapp](./webapp/): The main "executable". This is what the Torii application "sees". diff --git a/torii-client/.browserslistrc b/torii-client/webapp/.browserslistrc similarity index 100% rename from torii-client/.browserslistrc rename to torii-client/webapp/.browserslistrc diff --git a/torii-client/.eslintrc.js b/torii-client/webapp/.eslintrc.js similarity index 100% rename from torii-client/.eslintrc.js rename to torii-client/webapp/.eslintrc.js diff --git a/torii-client/.gitignore b/torii-client/webapp/.gitignore similarity index 100% rename from torii-client/.gitignore rename to torii-client/webapp/.gitignore diff --git a/torii-client/.prettierrc b/torii-client/webapp/.prettierrc similarity index 100% rename from torii-client/.prettierrc rename to torii-client/webapp/.prettierrc diff --git a/torii-client/webapp/README.md b/torii-client/webapp/README.md new file mode 100644 index 0000000..ed94801 --- /dev/null +++ b/torii-client/webapp/README.md @@ -0,0 +1,24 @@ +# torii-client + +## Project setup +``` +npm install +``` + +### Compiles and hot-reloads for development +``` +npm run serve +``` + +### Compiles and minifies for production +``` +npm run build +``` + +### Lints and fixes files +``` +npm run lint +``` + +### Customize configuration +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/torii-client/index.html b/torii-client/webapp/index.html similarity index 100% rename from torii-client/index.html rename to torii-client/webapp/index.html diff --git a/torii-client/package.json b/torii-client/webapp/package.json similarity index 98% rename from torii-client/package.json rename to torii-client/webapp/package.json index 159ad08..28c4339 100644 --- a/torii-client/package.json +++ b/torii-client/webapp/package.json @@ -1,5 +1,5 @@ { - "name": "torii-client", + "name": "@torii/webapp", "version": "0.1.0", "private": true, "main": "src/main.ts", diff --git a/torii-client/public/favicon.ico b/torii-client/webapp/public/favicon.ico similarity index 100% rename from torii-client/public/favicon.ico rename to torii-client/webapp/public/favicon.ico diff --git a/torii-client/public/index.html b/torii-client/webapp/public/index.html similarity index 100% rename from torii-client/public/index.html rename to torii-client/webapp/public/index.html diff --git a/torii-client/src/App.vue b/torii-client/webapp/src/App.vue similarity index 100% rename from torii-client/src/App.vue rename to torii-client/webapp/src/App.vue diff --git a/torii-client/src/assets/logo.png b/torii-client/webapp/src/assets/logo.png similarity index 100% rename from torii-client/src/assets/logo.png rename to torii-client/webapp/src/assets/logo.png diff --git a/torii-client/src/components/LanguageSelect.vue b/torii-client/webapp/src/components/LanguageSelect.vue similarity index 100% rename from torii-client/src/components/LanguageSelect.vue rename to torii-client/webapp/src/components/LanguageSelect.vue diff --git a/torii-client/src/components/article/MarkdownEditor.vue b/torii-client/webapp/src/components/article/MarkdownEditor.vue similarity index 100% rename from torii-client/src/components/article/MarkdownEditor.vue rename to torii-client/webapp/src/components/article/MarkdownEditor.vue diff --git a/torii-client/src/components/article/MarkdownEditorAutocomplete.vue b/torii-client/webapp/src/components/article/MarkdownEditorAutocomplete.vue similarity index 100% rename from torii-client/src/components/article/MarkdownEditorAutocomplete.vue rename to torii-client/webapp/src/components/article/MarkdownEditorAutocomplete.vue diff --git a/torii-client/src/components/article/autocomplete-extension.ts b/torii-client/webapp/src/components/article/autocomplete-extension.ts similarity index 100% rename from torii-client/src/components/article/autocomplete-extension.ts rename to torii-client/webapp/src/components/article/autocomplete-extension.ts diff --git a/torii-client/src/components/image/ImageEditor.vue b/torii-client/webapp/src/components/image/ImageEditor.vue similarity index 100% rename from torii-client/src/components/image/ImageEditor.vue rename to torii-client/webapp/src/components/image/ImageEditor.vue diff --git a/torii-client/src/composables/recentProjects.ts b/torii-client/webapp/src/composables/recentProjects.ts similarity index 100% rename from torii-client/src/composables/recentProjects.ts rename to torii-client/webapp/src/composables/recentProjects.ts diff --git a/torii-client/src/composables/settings-window.ts b/torii-client/webapp/src/composables/settings-window.ts similarity index 100% rename from torii-client/src/composables/settings-window.ts rename to torii-client/webapp/src/composables/settings-window.ts diff --git a/torii-client/src/composables/watch-locale.ts b/torii-client/webapp/src/composables/watch-locale.ts similarity index 100% rename from torii-client/src/composables/watch-locale.ts rename to torii-client/webapp/src/composables/watch-locale.ts diff --git a/torii-client/src/locales/en.json b/torii-client/webapp/src/locales/en.json similarity index 100% rename from torii-client/src/locales/en.json rename to torii-client/webapp/src/locales/en.json diff --git a/torii-client/src/locales/jp.json b/torii-client/webapp/src/locales/jp.json similarity index 100% rename from torii-client/src/locales/jp.json rename to torii-client/webapp/src/locales/jp.json diff --git a/torii-client/src/locales/zh.json b/torii-client/webapp/src/locales/zh.json similarity index 100% rename from torii-client/src/locales/zh.json rename to torii-client/webapp/src/locales/zh.json diff --git a/torii-client/src/main.ts b/torii-client/webapp/src/main.ts similarity index 100% rename from torii-client/src/main.ts rename to torii-client/webapp/src/main.ts diff --git a/torii-client/src/router/index.ts b/torii-client/webapp/src/router/index.ts similarity index 100% rename from torii-client/src/router/index.ts rename to torii-client/webapp/src/router/index.ts diff --git a/torii-client/src/shims-vue.d.ts b/torii-client/webapp/src/shims-vue.d.ts similarity index 100% rename from torii-client/src/shims-vue.d.ts rename to torii-client/webapp/src/shims-vue.d.ts diff --git a/torii-client/src/stores/settings.ts b/torii-client/webapp/src/stores/settings.ts similarity index 100% rename from torii-client/src/stores/settings.ts rename to torii-client/webapp/src/stores/settings.ts diff --git a/torii-client/src/styles/global.scss b/torii-client/webapp/src/styles/global.scss similarity index 100% rename from torii-client/src/styles/global.scss rename to torii-client/webapp/src/styles/global.scss diff --git a/torii-client/src/types.d.ts b/torii-client/webapp/src/types.d.ts similarity index 100% rename from torii-client/src/types.d.ts rename to torii-client/webapp/src/types.d.ts diff --git a/torii-client/src/ui/UIDropRegion.vue b/torii-client/webapp/src/ui/UIDropRegion.vue similarity index 100% rename from torii-client/src/ui/UIDropRegion.vue rename to torii-client/webapp/src/ui/UIDropRegion.vue diff --git a/torii-client/src/ui/UIFileTree.vue b/torii-client/webapp/src/ui/UIFileTree.vue similarity index 100% rename from torii-client/src/ui/UIFileTree.vue rename to torii-client/webapp/src/ui/UIFileTree.vue diff --git a/torii-client/src/ui/UISelect.vue b/torii-client/webapp/src/ui/UISelect.vue similarity index 100% rename from torii-client/src/ui/UISelect.vue rename to torii-client/webapp/src/ui/UISelect.vue diff --git a/torii-client/src/ui/UISpanInput.vue b/torii-client/webapp/src/ui/UISpanInput.vue similarity index 100% rename from torii-client/src/ui/UISpanInput.vue rename to torii-client/webapp/src/ui/UISpanInput.vue diff --git a/torii-client/src/ui/UITree.vue b/torii-client/webapp/src/ui/UITree.vue similarity index 100% rename from torii-client/src/ui/UITree.vue rename to torii-client/webapp/src/ui/UITree.vue diff --git a/torii-client/src/views/AboutView.vue b/torii-client/webapp/src/views/AboutView.vue similarity index 100% rename from torii-client/src/views/AboutView.vue rename to torii-client/webapp/src/views/AboutView.vue diff --git a/torii-client/src/views/HomeView.vue b/torii-client/webapp/src/views/HomeView.vue similarity index 100% rename from torii-client/src/views/HomeView.vue rename to torii-client/webapp/src/views/HomeView.vue diff --git a/torii-client/src/views/RecentProjectsView.vue b/torii-client/webapp/src/views/RecentProjectsView.vue similarity index 100% rename from torii-client/src/views/RecentProjectsView.vue rename to torii-client/webapp/src/views/RecentProjectsView.vue diff --git a/torii-client/src/views/project/ProjectView.vue b/torii-client/webapp/src/views/project/ProjectView.vue similarity index 100% rename from torii-client/src/views/project/ProjectView.vue rename to torii-client/webapp/src/views/project/ProjectView.vue diff --git a/torii-client/src/views/settings/GeneralSettingsView.vue b/torii-client/webapp/src/views/settings/GeneralSettingsView.vue similarity index 100% rename from torii-client/src/views/settings/GeneralSettingsView.vue rename to torii-client/webapp/src/views/settings/GeneralSettingsView.vue diff --git a/torii-client/src/views/settings/SettingsView.vue b/torii-client/webapp/src/views/settings/SettingsView.vue similarity index 100% rename from torii-client/src/views/settings/SettingsView.vue rename to torii-client/webapp/src/views/settings/SettingsView.vue diff --git a/torii-client/src/views/settings/ThemeSettingsView.vue b/torii-client/webapp/src/views/settings/ThemeSettingsView.vue similarity index 100% rename from torii-client/src/views/settings/ThemeSettingsView.vue rename to torii-client/webapp/src/views/settings/ThemeSettingsView.vue diff --git a/torii-client/tsconfig.json b/torii-client/webapp/tsconfig.json similarity index 85% rename from torii-client/tsconfig.json rename to torii-client/webapp/tsconfig.json index 4795d0b..4d39d02 100644 --- a/torii-client/tsconfig.json +++ b/torii-client/webapp/tsconfig.json @@ -25,8 +25,8 @@ // "baseUrl": "src", "paths": { - "@/*": ["./src/*"] + "@/*": ["webapp/src/*"] } }, - "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] + "include": ["webapp/src/**/*.ts", "webapp/src/**/*.tsx", "webapp/src/**/*.vue"] } diff --git a/torii-client/typedoc.json b/torii-client/webapp/typedoc.json similarity index 100% rename from torii-client/typedoc.json rename to torii-client/webapp/typedoc.json diff --git a/torii-client/vite.config.ts b/torii-client/webapp/vite.config.ts similarity index 100% rename from torii-client/vite.config.ts rename to torii-client/webapp/vite.config.ts diff --git a/torii-workspaces/welcome/Changelog.md b/torii-workspaces/welcome/Changelog.md index 0b25691..a70757e 100644 --- a/torii-workspaces/welcome/Changelog.md +++ b/torii-workspaces/welcome/Changelog.md @@ -4,7 +4,9 @@ ### [v0.0.0-dev9](https://github.com/Anatoly03/Torii/releases/tag/app-v0.0.0-dev9) -- TBA +- Add a button to switch between Edit Mode and Preview Mode. +- Preview Mode hides the template grids for image-like components. +- Add a new workspace "Writing Theory". It contains some selected resources which are useful for fiction writing. Currently it contains an unfinished document on plot structure. --- @@ -56,7 +58,7 @@ --- -### [v0.0.0-dev3](https://github.com/Anatoly03/Torii/releases/tag/app-v0.0.0-dev3) +### [v0.0.0-dev3](https://github.com/Anatoly03/Torii/releases/tag/app-v0.0.0-dev3) - Added technical functionality to display one header image. From 9a969eb39b21101beab5ca2bd868689a874c77e8 Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Tue, 11 Aug 2026 11:27:15 +0200 Subject: [PATCH 2/7] refactor roadmap and contributing --- CONTRIBUTING.md | 12 ++++++++++-- ROADMAP.md | 13 +++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0d010e6..7d8688b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -29,6 +29,14 @@ go run src/main.go serve ### Pull Request Rules -- **No vibes.** You are allowed to use smart, contextless autocompletion but code which has been subject to agent generation is not allowed in this repository. +- **No vibes.** You are allowed to use smart, contextless autocompletion and ask smart assistants for planning and code review. However code which has been subject to agent generation is categorically not allowed in this repository. -- **English Codebase.** We allow to interact with this repositories issuesses and discussions in different languages. However excluded are all commit messages, source code and the title and first message in a Pull Request, which have to be in English. +- **English Codebase.** We allow to interact with this repositories issuesses, discussions and comments in different languages. However excluded are all commit messages, source code and the title and first message in a Pull Request, which have to be in English. + +- **No obfuscastions.** Code using obfuscations for the sake of being unreadable is not allowed. Performance-optimized code has to be clearly documented with comments. + +- **Citations.** Code retrieved from external websites like StackOverflow have to be cited in the codebase. A citation is a comment with a link above the cited code segment. Links that helped you fix bugs or helped you choose an algorithm or approach are welcomed. + +- **Documentation.** All code is subject to exhaustive documentation. Make sure the formatting is not broken for documentation generators. For functions include example and usage. We try to keep a 1:1 to 1:2 (code lines:documentation) ratio. + +- **Rules are non-exhaustive.** The administrative team of this codebase reserves the right to make up new written rules when "unspoken rules" are broken. The "unspoken rules" include: Be Nice, Keep the Code Clean, Follow Existing Patterns or Evolve New Maintainable Patterns. diff --git a/ROADMAP.md b/ROADMAP.md index ce5d32e..9d2fa8a 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -90,8 +90,17 @@ The first stage of the project is to create a simple file browser like applicati ### `v0.0.0-dev9` [NEXT] - [ ] Client Refactoring (vue app and plugins first steps) - - [ ] Plugin: A separate non-app code module. - - [ ] Views: A panel which can be defined by a module. + - [ ] Phase 1: Plugin API Core + - [ ] `ToriiPlugin`: A separate library module defining plugin. + - [ ] Define plugin lifecycle hooks (`onInit`, `onRecordOpen`, `onComponentUpdate`, etc.) + - [ ] Define anchor point constants. Anchor points are views which can be extended by plugins. + - [ ] `PluginManager` with `register` new plugins and `getAnchorView()` to render an anchor screen. + - [ ] Phase 2: Call Plugin API + - [ ] Define a Vue anchor component (renderer) and place some in the app. + - [ ] Pass workspace context to plugins. + - [ ] Phase 3: Plugin Extraction + - [ ] `word-count` + - [ ] `recent-projects` - [x] Client Documentation (Typedoc Infrastructure) - [ ] Breadcrumb Header - [x] Expand Footer with Edit and View mode. From 4df11d8446b75c10b6aa6b61c9b29136cc2c1edf Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Tue, 11 Aug 2026 11:34:45 +0200 Subject: [PATCH 3/7] fix import issuesses --- .../webapp/src/components/article/MarkdownEditor.vue | 2 +- torii-desktop/src/record/mod.rs | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/torii-client/webapp/src/components/article/MarkdownEditor.vue b/torii-client/webapp/src/components/article/MarkdownEditor.vue index c490e63..57fbd9a 100644 --- a/torii-client/webapp/src/components/article/MarkdownEditor.vue +++ b/torii-client/webapp/src/components/article/MarkdownEditor.vue @@ -37,7 +37,7 @@ import { type SuggestionItem, } from './autocomplete-extension'; import MarkdownEditorAutocomplete from './MarkdownEditorAutocomplete.vue'; -import { Record } from 'types'; +import type { Record } from '../../types.d.ts'; const props = defineProps<{ record: Record; diff --git a/torii-desktop/src/record/mod.rs b/torii-desktop/src/record/mod.rs index f4e92a9..2189d80 100644 --- a/torii-desktop/src/record/mod.rs +++ b/torii-desktop/src/record/mod.rs @@ -5,10 +5,7 @@ mod serde; use crate::{Component, components::get_all_components, workspace::Workspace}; use path_normalizer::PathNormalizeExt; -use std::{ - collections::HashSet, - path::{Path, PathBuf}, -}; +use std::{collections::HashSet, path::PathBuf}; /// The record struct represents a Torii record. #[derive(Debug, Clone, PartialEq, Eq, Hash)] From af49a0fd066121d2d3aa63d3f5f1e22ddef2ba9b Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Tue, 11 Aug 2026 11:59:21 +0200 Subject: [PATCH 4/7] add plugin core module --- package-lock.json | 9 ++++++++ torii-client/plugin-core/.prettierrc | 6 +++++ torii-client/plugin-core/package.json | 6 +++++ torii-client/plugin-core/src/lib.ts | 1 + torii-client/plugin-core/tsconfig.json | 32 ++++++++++++++++++++++++++ torii-client/webapp/package.json | 1 + torii-client/webapp/src/main.ts | 3 +++ torii-client/webapp/tsconfig.json | 4 ++-- 8 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 torii-client/plugin-core/.prettierrc create mode 100644 torii-client/plugin-core/package.json create mode 100644 torii-client/plugin-core/src/lib.ts create mode 100644 torii-client/plugin-core/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 590648f..bb84c5b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1484,6 +1484,10 @@ "vue": "^3.0.0" } }, + "node_modules/@torii/plugin-core": { + "resolved": "torii-client/plugin-core", + "link": true + }, "node_modules/@torii/webapp": { "resolved": "torii-client/webapp", "link": true @@ -11581,6 +11585,10 @@ "vue": "^3.2.0" } }, + "torii-client/plugin-core": { + "name": "@torii/plugin-core", + "version": "0.1.0" + }, "torii-client/webapp": { "name": "@torii/webapp", "version": "0.1.0", @@ -11594,6 +11602,7 @@ "@tiptap/pm": "^3.27.1", "@tiptap/starter-kit": "^3.27.1", "@tiptap/vue-3": "^3.27.1", + "@torii/plugin-core": "file:../plugin-core", "pinia": "^3.0.4", "typedoc": "^0.28.20", "typedoc-plugin-vue": "^1.5.1", diff --git a/torii-client/plugin-core/.prettierrc b/torii-client/plugin-core/.prettierrc new file mode 100644 index 0000000..a24df35 --- /dev/null +++ b/torii-client/plugin-core/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "tabWidth": 4, + "singleQuote": true, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/torii-client/plugin-core/package.json b/torii-client/plugin-core/package.json new file mode 100644 index 0000000..8f32ccd --- /dev/null +++ b/torii-client/plugin-core/package.json @@ -0,0 +1,6 @@ +{ + "name": "@torii/plugin-core", + "version": "0.1.0", + "private": true, + "main": "src/lib.ts" +} diff --git a/torii-client/plugin-core/src/lib.ts b/torii-client/plugin-core/src/lib.ts new file mode 100644 index 0000000..a78b6d5 --- /dev/null +++ b/torii-client/plugin-core/src/lib.ts @@ -0,0 +1 @@ +export const world = 'Hello, World!'; diff --git a/torii-client/plugin-core/tsconfig.json b/torii-client/plugin-core/tsconfig.json new file mode 100644 index 0000000..4795d0b --- /dev/null +++ b/torii-client/plugin-core/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + // general + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + // file handling + + // "baseUrl": "src", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/torii-client/webapp/package.json b/torii-client/webapp/package.json index 28c4339..b8b4a3a 100644 --- a/torii-client/webapp/package.json +++ b/torii-client/webapp/package.json @@ -19,6 +19,7 @@ "@tiptap/pm": "^3.27.1", "@tiptap/starter-kit": "^3.27.1", "@tiptap/vue-3": "^3.27.1", + "@torii/plugin-core": "file:../plugin-core", "pinia": "^3.0.4", "typedoc": "^0.28.20", "typedoc-plugin-vue": "^1.5.1", diff --git a/torii-client/webapp/src/main.ts b/torii-client/webapp/src/main.ts index 2363361..f5f3f04 100644 --- a/torii-client/webapp/src/main.ts +++ b/torii-client/webapp/src/main.ts @@ -1,12 +1,15 @@ import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; +import { world } from '@torii/plugin-core'; import { createI18n } from 'vue-i18n'; import en from './locales/en.json'; import jp from './locales/jp.json'; import zh from './locales/zh.json'; +console.log(world); + const i18n = createI18n({ legacy: false, locale: 'en', diff --git a/torii-client/webapp/tsconfig.json b/torii-client/webapp/tsconfig.json index 4d39d02..4795d0b 100644 --- a/torii-client/webapp/tsconfig.json +++ b/torii-client/webapp/tsconfig.json @@ -25,8 +25,8 @@ // "baseUrl": "src", "paths": { - "@/*": ["webapp/src/*"] + "@/*": ["./src/*"] } }, - "include": ["webapp/src/**/*.ts", "webapp/src/**/*.tsx", "webapp/src/**/*.vue"] + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] } From 2f27cc1dee6715faf3aee7e5fb0f6fa31fc4e08a Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Tue, 11 Aug 2026 12:16:14 +0200 Subject: [PATCH 5/7] add `ToriiPlugin` base grid --- torii-client/plugin-core/src/lib.ts | 2 +- torii-client/plugin-core/src/plugin.ts | 54 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 torii-client/plugin-core/src/plugin.ts diff --git a/torii-client/plugin-core/src/lib.ts b/torii-client/plugin-core/src/lib.ts index a78b6d5..044920f 100644 --- a/torii-client/plugin-core/src/lib.ts +++ b/torii-client/plugin-core/src/lib.ts @@ -1 +1 @@ -export const world = 'Hello, World!'; +export const world = 'Hello, Torii Plugin API!'; diff --git a/torii-client/plugin-core/src/plugin.ts b/torii-client/plugin-core/src/plugin.ts new file mode 100644 index 0000000..cb46cbf --- /dev/null +++ b/torii-client/plugin-core/src/plugin.ts @@ -0,0 +1,54 @@ +/** + * @file plugin.ts + * @brief Defines the Torii Plugin extensible. + */ + +export interface ToriiPluginSettings { + onInit?: () => void; + onDestroy?: () => void; +} + +/** + * @brief A Torii plugin is a scope of code, with its' own lifecycle, that + * can be loaded, interacted with and offloaded by Toriis' internal plugin + * loader. + */ +export class ToriiPlugin { + // + // ATTRIBUTES, INTERNAL PLUGIN SETTINGS + // + + // + // CONSTRUCTOR + // + constructor() {} + + // + // STATIC FUNCTIONS + // + + /** + * @brief Quickly create a new, small Torii plugin from the provided + * settings object. For more complex Torii types, consider extending + * the class. + * + * @example + * + * ToriiPlugin.create({ + * // TODO + * }); + * + * @returns Newly created Torii Plugin. + */ + public static create(_settings: ToriiPluginSettings): ToriiPlugin { + const plugin = new ToriiPlugin(); + + // TODO + + return plugin; + } + + // + // METHODS + // +} From a19cc356edbac972224d7f547215328b41c5f6df Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Tue, 18 Aug 2026 13:38:10 +0200 Subject: [PATCH 6/7] refactor --- torii-client/plugin-core/src/plugin.ts | 128 ++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 11 deletions(-) diff --git a/torii-client/plugin-core/src/plugin.ts b/torii-client/plugin-core/src/plugin.ts index cb46cbf..2c6742c 100644 --- a/torii-client/plugin-core/src/plugin.ts +++ b/torii-client/plugin-core/src/plugin.ts @@ -3,9 +3,60 @@ * @brief Defines the Torii Plugin extensible. */ +/** + * Quick-creation settings for the static {@link ToriiPlugin.create()} + * method. + */ export interface ToriiPluginSettings { - onInit?: () => void; - onDestroy?: () => void; + /** + * @brief The unique identifier of the plugin, consisting of letters, + * numerics and dashes. You can prefix the plugin with a custom scope + * if needed. For example, `my-custom-scope:custom-plugin` would be an + * allowed plugin name. + * + * @note The prefix `core:` should only be used by libraries internal + * to the Torii project. + * + * @example + * + * { + * PLUGIN_ID: "core:markdown:hyperlinks", + * } + */ + PLUGIN_ID: string; + + // /** + // * @brief Callback to be invoked when the plugin is initialized. This + // * can happen only once if the plugin is initialized at start. + // * + // * @note You should **not** compute anything in this function that + // * "activates" the plugin. This function is explicitly only for logic + // * that should only run once in the lifetime of the plugin. + // * + // * For setup behaviour when a plugin (that was previously deactivated) + // * is enabled again see {@link ToriiPluginSettings.onActivate|onActivate}. + // */ + // onInit?: () => void; + + /** + * @brief Callback to be invoked when the plugin is activated. This + * can happen multiple times over the runtime of the plugin. + * + * For destructor behaviour when the plugin is deactivated, you should + * use {@link ToriiPluginSettings.onDeactivate|onDeactivate}. + */ + onActivate?: () => void; + + /** + * @brief Callback to be invoked when the plugin is deactivated, either + * by application closing or manual plugin deactivation by the user. + * + * For constructor behaviour when the plugin is activated, you should + * use {@link ToriiPluginSettings.onActivate|onActivate}. + */ + onDeactivate?: () => void; + + // onDestroy?: () => void; } /** @@ -15,35 +66,66 @@ export interface ToriiPluginSettings { */ export class ToriiPlugin { // - // ATTRIBUTES, INTERNAL PLUGIN SETTINGS + // ATTRIBUTES [INTERNAL PLUGIN CONSTANTS] + // + + /** + * @brief The unique identifier of the plugin, consisting of letters, + * numerics and dashes. You can prefix the plugin with a custom scope + * if needed. For example, `my-custom-scope:custom-plugin` would be an + * allowed plugin name. + * + * @note The prefix `core:` should only be used by libraries internal + * to the Torii project. + * + * @example + * + * { + * PLUGIN_ID: "core:markdown:hyperlinks", + * } + */ + public PLUGIN_ID: string; + + // + // Handles + // + + #onActivateHandlers: (() => void)[] = []; + #onDeactivateHandlers: (() => void)[] = []; + + // + // ATTRIBUTES [CALLBACKS] // // // CONSTRUCTOR // - constructor() {} + constructor(pluginId: string) { + this.PLUGIN_ID = pluginId; + } // // STATIC FUNCTIONS // /** - * @brief Quickly create a new, small Torii plugin from the provided + * @brief Quickly create a new, small Torii plugin from the provided * settings object. For more complex Torii types, consider extending * the class. - * + * * @example - * + * * ToriiPlugin.create({ * // TODO * }); - * + * * @returns Newly created Torii Plugin. */ - public static create(_settings: ToriiPluginSettings): ToriiPlugin { - const plugin = new ToriiPlugin(); + public static create(settings: ToriiPluginSettings): ToriiPlugin { + const plugin = new ToriiPlugin(settings.PLUGIN_ID); - // TODO + if (settings.onActivate) plugin.onActivate(settings.onActivate); + if (settings.onDeactivate) plugin.onDeactivate(settings.onDeactivate); return plugin; } @@ -51,4 +133,28 @@ export class ToriiPlugin { // // METHODS // + + /** + * @brief Register a callback to be invoked when the plugin is + * activated. This can happen multiple times over the runtime + * of the plugin. + * + * For destructor behaviour when the plugin is deactivated, you should + * use {@link ToriiPluginSettings.onDeactivate|onDeactivate}. + */ + public onActivate(callback: () => void) { + this.#onActivateHandlers.push(callback); + } + + /** + * @brief Register a callback to be invoked when the plugin is + * deactivated, either by application closing or manual plugin + * deactivation by the user. + * + * For constructor behaviour when the plugin is activated, you should + * use {@link ToriiPluginSettings.onActivate|onActivate}. + */ + public onDeactivate(callback: () => void) { + this.#onDeactivateHandlers.push(callback); + } } From 3bf9314ecfa405cb8f3dc7c7a0771678e2b54b97 Mon Sep 17 00:00:00 2001 From: Anatoly Wein Date: Sun, 30 Aug 2026 12:27:33 +0200 Subject: [PATCH 7/7] add simple plugin --- ROADMAP.md | 2 +- package-lock.json | 121 ++++++++----- torii-client/plugin-core/package.json | 5 +- torii-client/plugin-core/src/lib.ts | 10 +- torii-client/plugin-core/src/plugin-events.ts | 32 ++++ torii-client/plugin-core/src/plugin-loader.ts | 42 +++++ torii-client/plugin-core/src/plugin.ts | 167 +++++++++++++++--- torii-client/plugin-debug/.prettierrc | 6 + torii-client/plugin-debug/package.json | 10 ++ torii-client/plugin-debug/src/lib.ts | 23 +++ torii-client/plugin-debug/tsconfig.json | 32 ++++ torii-client/webapp/package.json | 1 + torii-client/webapp/src/App.vue | 2 + .../src/components/image/ImageEditor.vue | 2 +- torii-client/webapp/src/main.ts | 3 - torii-client/webapp/src/services/plugins.ts | 13 ++ .../webapp/src/views/RecentProjectsView.vue | 1 + .../webapp/src/views/project/ProjectView.vue | 11 +- 18 files changed, 411 insertions(+), 72 deletions(-) create mode 100644 torii-client/plugin-core/src/plugin-events.ts create mode 100644 torii-client/plugin-core/src/plugin-loader.ts create mode 100644 torii-client/plugin-debug/.prettierrc create mode 100644 torii-client/plugin-debug/package.json create mode 100644 torii-client/plugin-debug/src/lib.ts create mode 100644 torii-client/plugin-debug/tsconfig.json create mode 100644 torii-client/webapp/src/services/plugins.ts diff --git a/ROADMAP.md b/ROADMAP.md index 9d2fa8a..3097f96 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -91,7 +91,7 @@ The first stage of the project is to create a simple file browser like applicati - [ ] Client Refactoring (vue app and plugins first steps) - [ ] Phase 1: Plugin API Core - - [ ] `ToriiPlugin`: A separate library module defining plugin. + - [x] `ToriiPlugin`: A separate library module defining plugin. - [ ] Define plugin lifecycle hooks (`onInit`, `onRecordOpen`, `onComponentUpdate`, etc.) - [ ] Define anchor point constants. Anchor points are views which can be extended by plugins. - [ ] `PluginManager` with `register` new plugins and `getAnchorView()` to render an anchor screen. diff --git a/package-lock.json b/package-lock.json index bb84c5b..b9c5af8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -349,10 +349,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.7", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.29.7" + "@babel/types": "^7.29.8" }, "bin": { "parser": "bin/babel-parser.js" @@ -493,7 +495,9 @@ } }, "node_modules/@babel/types": { - "version": "7.29.7", + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.29.7", @@ -1488,6 +1492,10 @@ "resolved": "torii-client/plugin-core", "link": true }, + "node_modules/@torii/plugin-debug": { + "resolved": "torii-client/plugin-debug", + "link": true + }, "node_modules/@torii/webapp": { "resolved": "torii-client/webapp", "link": true @@ -2280,45 +2288,53 @@ "license": "ISC" }, "node_modules/@vue/compiler-core": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.41.tgz", + "integrity": "sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/shared": "3.5.39", + "@babel/parser": "^7.29.8", + "@vue/shared": "3.5.41", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz", + "integrity": "sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-core": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz", + "integrity": "sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.7", - "@vue/compiler-core": "3.5.39", - "@vue/compiler-dom": "3.5.39", - "@vue/compiler-ssr": "3.5.39", - "@vue/shared": "3.5.39", + "@babel/parser": "^7.29.8", + "@vue/compiler-core": "3.5.41", + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-ssr": "3.5.41", + "@vue/shared": "3.5.41", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.15", + "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz", + "integrity": "sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-dom": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/component-compiler-utils": { @@ -2456,43 +2472,51 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.41.tgz", + "integrity": "sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.39" + "@vue/shared": "3.5.41" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.41.tgz", + "integrity": "sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/reactivity": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz", + "integrity": "sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.39", - "@vue/runtime-core": "3.5.39", - "@vue/shared": "3.5.39", + "@vue/reactivity": "3.5.41", + "@vue/runtime-core": "3.5.41", + "@vue/shared": "3.5.41", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.41.tgz", + "integrity": "sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.39", - "@vue/shared": "3.5.39" - }, - "peerDependencies": { - "vue": "3.5.39" + "@vue/compiler-ssr": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/shared": "3.5.41" } }, "node_modules/@vue/shared": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.41.tgz", + "integrity": "sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA==", "license": "MIT" }, "node_modules/@vue/vue-loader-v15": { @@ -10585,14 +10609,16 @@ } }, "node_modules/vue": { - "version": "3.5.39", + "version": "3.5.41", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.41.tgz", + "integrity": "sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.39", - "@vue/compiler-sfc": "3.5.39", - "@vue/runtime-dom": "3.5.39", - "@vue/server-renderer": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-dom": "3.5.41", + "@vue/compiler-sfc": "3.5.41", + "@vue/runtime-dom": "3.5.41", + "@vue/server-renderer": "3.5.41", + "@vue/shared": "3.5.41" }, "peerDependencies": { "typescript": "*" @@ -11587,7 +11613,18 @@ }, "torii-client/plugin-core": { "name": "@torii/plugin-core", - "version": "0.1.0" + "version": "0.1.0", + "dependencies": { + "vue": "^3.5.41" + } + }, + "torii-client/plugin-debug": { + "name": "@torii/plugin-debug", + "version": "0.1.0", + "dependencies": { + "@torii/plugin-core": "file:../plugin-core", + "vue": "^3.5.41" + } }, "torii-client/webapp": { "name": "@torii/webapp", diff --git a/torii-client/plugin-core/package.json b/torii-client/plugin-core/package.json index 8f32ccd..0f625ed 100644 --- a/torii-client/plugin-core/package.json +++ b/torii-client/plugin-core/package.json @@ -2,5 +2,8 @@ "name": "@torii/plugin-core", "version": "0.1.0", "private": true, - "main": "src/lib.ts" + "main": "src/lib.ts", + "dependencies": { + "vue": "^3.5.41" + } } diff --git a/torii-client/plugin-core/src/lib.ts b/torii-client/plugin-core/src/lib.ts index 044920f..dac7dfb 100644 --- a/torii-client/plugin-core/src/lib.ts +++ b/torii-client/plugin-core/src/lib.ts @@ -1 +1,9 @@ -export const world = 'Hello, Torii Plugin API!'; +import ToriiPlugin from "./plugin"; +import ToriiPluginLoader from "./plugin-loader"; +import ToriiPluginEvents from "./plugin-events"; + +export { + ToriiPlugin, + ToriiPluginLoader, + type ToriiPluginEvents +}; diff --git a/torii-client/plugin-core/src/plugin-events.ts b/torii-client/plugin-core/src/plugin-events.ts new file mode 100644 index 0000000..a26fcc8 --- /dev/null +++ b/torii-client/plugin-core/src/plugin-events.ts @@ -0,0 +1,32 @@ +/** + * @file plugin-events.ts + * @brief Defines all internally-understood Torii plugin events. + */ + +/** + * List of internallly-understood Torii events. A plugin can always emit custom + * events, but these will be ignored by internal Torii plugins. + */ +export type ToriiPluginEvents = { + // plugin lifecycle + ['plugin-activate']: () => void; + ['plugin-deactivate']: () => void; + + // workspace lifecycle + ['workspace-open']: (path: string) => void, + ['workspace-close']: (path: string) => void, + + // record lifecycle + ['record-open']: () => void; + ['record-close']: () => void; + ['record-create']: () => void; + ['record-rename']: () => void; + ['record-delete']: () => void; + + // records' individual component lifecycle + ['record-component-create']: () => void; + ['record-component-update']: () => void; + ['record-component-delete']: () => void; +}; + +export default ToriiPluginEvents; diff --git a/torii-client/plugin-core/src/plugin-loader.ts b/torii-client/plugin-core/src/plugin-loader.ts new file mode 100644 index 0000000..ed187cb --- /dev/null +++ b/torii-client/plugin-core/src/plugin-loader.ts @@ -0,0 +1,42 @@ +/** + * @file plugin-loader.ts + */ + +import ToriiPlugin from './plugin'; +import ToriiPluginEvents from './plugin-events'; + +/** + * @brief A Torii plugin loader is a scope of code. + */ +export class ToriiPluginLoader { + /** + * @brief Currently installed plugins. + */ + private readonly plugins: ToriiPlugin[] = []; + + /** + * @todo + */ + constructor() {} + + /** + * @brief Install a plugin. + */ + public install(plugin: ToriiPlugin) { + this.plugins.push(plugin); + plugin.emit('plugin-activate'); + } + + /** + * @brief Emits an event. + */ + public emit( + e: Event, + ...args: Parameters + ): this { + this.plugins.forEach((plugin) => plugin.emit(e, ...args)); + return this; + } +} + +export default ToriiPluginLoader; diff --git a/torii-client/plugin-core/src/plugin.ts b/torii-client/plugin-core/src/plugin.ts index 2c6742c..31a9fe6 100644 --- a/torii-client/plugin-core/src/plugin.ts +++ b/torii-client/plugin-core/src/plugin.ts @@ -3,6 +3,8 @@ * @brief Defines the Torii Plugin extensible. */ +import ToriiPluginEvents from './plugin-events'; + /** * Quick-creation settings for the static {@link ToriiPlugin.create()} * method. @@ -20,10 +22,23 @@ export interface ToriiPluginSettings { * @example * * { - * PLUGIN_ID: "core:markdown:hyperlinks", + * id: "core:markdown:hyperlinks", * } */ - PLUGIN_ID: string; + id: string; + + /** + * Semver string of the plugin version, consisting of at least major, + * minor and optionally patch. + * + * + * @example + * + * { + * version: "1.2.0-dev4", + * } + */ + version: string; // /** // * @brief Callback to be invoked when the plugin is initialized. This @@ -81,17 +96,36 @@ export class ToriiPlugin { * @example * * { - * PLUGIN_ID: "core:markdown:hyperlinks", + * id: "core:markdown:hyperlinks", + * } + */ + public readonly pluginId: string; + + /** + * Semver string of the plugin version, consisting of at least major, + * minor and optionally patch. + * + * @example + * + * { + * version: "1.2.0-dev4", * } */ - public PLUGIN_ID: string; + public pluginVersion: string = '0.1.0'; // // Handles // - #onActivateHandlers: (() => void)[] = []; - #onDeactivateHandlers: (() => void)[] = []; + /** + * List of registered event handlers. The key is any understood Torii + * event name, and the handler is an array of functions which listen + * to the event. + */ + #handlers: Map< + keyof ToriiPluginEvents, + ToriiPluginEvents[keyof ToriiPluginEvents][] + > = new Map(); // // ATTRIBUTES [CALLBACKS] @@ -101,7 +135,7 @@ export class ToriiPlugin { // CONSTRUCTOR // constructor(pluginId: string) { - this.PLUGIN_ID = pluginId; + this.pluginId = pluginId; } // @@ -122,10 +156,12 @@ export class ToriiPlugin { * @returns Newly created Torii Plugin. */ public static create(settings: ToriiPluginSettings): ToriiPlugin { - const plugin = new ToriiPlugin(settings.PLUGIN_ID); + const plugin = new ToriiPlugin(settings.id); - if (settings.onActivate) plugin.onActivate(settings.onActivate); - if (settings.onDeactivate) plugin.onDeactivate(settings.onDeactivate); + if (settings.onActivate) + plugin.on('plugin-activate', settings.onActivate); + if (settings.onDeactivate) + plugin.on('plugin-deactivate', settings.onDeactivate); return plugin; } @@ -134,27 +170,116 @@ export class ToriiPlugin { // METHODS // + // TODO + + // + // EVENTS + // + /** - * @brief Register a callback to be invoked when the plugin is - * activated. This can happen multiple times over the runtime - * of the plugin. + * @brief Register a callback to be invoked when the plugin is activated. + * This can happen multiple times over the runtime of the plugin. * * For destructor behaviour when the plugin is deactivated, you should * use {@link ToriiPluginSettings.onDeactivate|onDeactivate}. */ - public onActivate(callback: () => void) { - this.#onActivateHandlers.push(callback); - } + on(e: 'plugin-activate', callback: () => void): this; /** - * @brief Register a callback to be invoked when the plugin is - * deactivated, either by application closing or manual plugin - * deactivation by the user. + * @brief Register a callback to be invoked when the plugin is deactivated, + * either by application closing or manual plugin deactivation by the user. * * For constructor behaviour when the plugin is activated, you should * use {@link ToriiPluginSettings.onActivate|onActivate}. */ - public onDeactivate(callback: () => void) { - this.#onDeactivateHandlers.push(callback); + on(e: 'plugin-deactivate', callback: () => void): this; + + // TODO workspace-open + // TODO workspace-close + + /** + * @brief Register a callback to be invoked when a record was opened. + * + * For behaviour when the record is closed, you should use + * {@link ToriiPluginSettings.onRecordClose|onRecordClose}. + */ + on(e: 'record-open', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a record was closed. When + * a new record is opened instead, the old record will be closed first. + * + * For behaviour when the record is opened, you should use + * {@link ToriiPluginSettings.onRecordOpen|onRecordOpen}. + */ + on(e: 'record-close', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a record was created. + */ + on(e: 'record-create', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a record was renamed. + */ + on(e: 'record-rename', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a record was deleted. + */ + on(e: 'record-delete', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a record was attached + * with a new component. + */ + on(e: 'component-create', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a records' component was + * modified. + */ + on(e: 'component-update', callback: () => void): this; + + /** + * @brief Register a callback to be invoked when a records' component was + * deleted. + */ + on(e: 'component-delete', callback: () => void): this; + + /** + * @brief Registers a new event handler. + * @param e Name of the event to listen for. When the plugin loader receives + * this event, the callback function will be invoked. + */ + public on( + e: Event, + callback: ToriiPluginEvents[Event] + ): this { + switch (this.#handlers.has(e)) { + case true: + this.#handlers.get(e)!.push(callback); + return this; + case false: + this.#handlers.set(e, [callback]); + return this; + } + } + + /** + * @brief Registers a new event handler. + * @param e Name of the event to listen for. When the plugin loader receives + * this event, the callback function will be invoked. + */ + public emit( + e: Event, + ...args: Parameters + ): this { + this.#handlers.get(e)?.forEach((callback: (...e: any) => void) => { + callback(...args); + }); + return this; } } + +export default ToriiPlugin; diff --git a/torii-client/plugin-debug/.prettierrc b/torii-client/plugin-debug/.prettierrc new file mode 100644 index 0000000..a24df35 --- /dev/null +++ b/torii-client/plugin-debug/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "tabWidth": 4, + "singleQuote": true, + "endOfLine": "auto" +} \ No newline at end of file diff --git a/torii-client/plugin-debug/package.json b/torii-client/plugin-debug/package.json new file mode 100644 index 0000000..c8efa35 --- /dev/null +++ b/torii-client/plugin-debug/package.json @@ -0,0 +1,10 @@ +{ + "name": "@torii/plugin-debug", + "version": "0.1.0", + "private": true, + "main": "src/lib.ts", + "dependencies": { + "vue": "^3.5.41", + "@torii/plugin-core": "file:../plugin-core" + } +} diff --git a/torii-client/plugin-debug/src/lib.ts b/torii-client/plugin-debug/src/lib.ts new file mode 100644 index 0000000..df1966d --- /dev/null +++ b/torii-client/plugin-debug/src/lib.ts @@ -0,0 +1,23 @@ +import { ToriiPlugin, ToriiPluginEvents } from '@torii/plugin-core'; + +class ToriiDebugPlugin extends ToriiPlugin { + public override pluginVersion = '0.1.0'; + + constructor() { + super('core:debug:plugin-debug'); + } + + /** + * @brief Print the received event information to the console. + */ + public override emit( + e: Event, + ...args: Parameters + ): this { + // super.emit(e, ...args); + console.debug(`[plugin-debug] Event '${e}':`, ...args); + return this; + } +} + +export default new ToriiDebugPlugin(); diff --git a/torii-client/plugin-debug/tsconfig.json b/torii-client/plugin-debug/tsconfig.json new file mode 100644 index 0000000..4795d0b --- /dev/null +++ b/torii-client/plugin-debug/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + // general + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + + // file handling + + // "baseUrl": "src", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/torii-client/webapp/package.json b/torii-client/webapp/package.json index b8b4a3a..2f23d06 100644 --- a/torii-client/webapp/package.json +++ b/torii-client/webapp/package.json @@ -20,6 +20,7 @@ "@tiptap/starter-kit": "^3.27.1", "@tiptap/vue-3": "^3.27.1", "@torii/plugin-core": "file:../plugin-core", + "@torii/plugin-debug": "file:../plugin-debug", "pinia": "^3.0.4", "typedoc": "^0.28.20", "typedoc-plugin-vue": "^1.5.1", diff --git a/torii-client/webapp/src/App.vue b/torii-client/webapp/src/App.vue index 017983a..1420904 100644 --- a/torii-client/webapp/src/App.vue +++ b/torii-client/webapp/src/App.vue @@ -6,6 +6,7 @@ import { onMounted, onUnmounted } from 'vue'; import { watchLocale } from './composables/watch-locale'; import { loadSettings } from './stores/settings.ts'; +import { usePlugins } from './services/plugins.ts'; watchLocale(); loadSettings(); @@ -17,6 +18,7 @@ function preventDefault(e: { preventDefault: () => void }) { onMounted(() => { document.addEventListener('dragover', preventDefault); document.addEventListener('drop', preventDefault); + usePlugins(); // activate singleton }); onUnmounted(() => { diff --git a/torii-client/webapp/src/components/image/ImageEditor.vue b/torii-client/webapp/src/components/image/ImageEditor.vue index 0b5a5b8..3866ea1 100644 --- a/torii-client/webapp/src/components/image/ImageEditor.vue +++ b/torii-client/webapp/src/components/image/ImageEditor.vue @@ -51,7 +51,7 @@ import { invoke } from '@tauri-apps/api/core'; import { open as openFileDialog } from '@tauri-apps/plugin-dialog'; import { NIcon, NSpin } from 'naive-ui'; import { CloseOutline, ImageOutline } from '@vicons/ionicons5'; -import { Record } from 'types'; +import type { Record } from '../../types.d.ts'; import UIDropRegion from '../../ui/UIDropRegion.vue'; const props = defineProps<{ diff --git a/torii-client/webapp/src/main.ts b/torii-client/webapp/src/main.ts index f5f3f04..2363361 100644 --- a/torii-client/webapp/src/main.ts +++ b/torii-client/webapp/src/main.ts @@ -1,15 +1,12 @@ import { createApp } from 'vue'; import App from './App.vue'; import router from './router'; -import { world } from '@torii/plugin-core'; import { createI18n } from 'vue-i18n'; import en from './locales/en.json'; import jp from './locales/jp.json'; import zh from './locales/zh.json'; -console.log(world); - const i18n = createI18n({ legacy: false, locale: 'en', diff --git a/torii-client/webapp/src/services/plugins.ts b/torii-client/webapp/src/services/plugins.ts new file mode 100644 index 0000000..549d644 --- /dev/null +++ b/torii-client/webapp/src/services/plugins.ts @@ -0,0 +1,13 @@ +import { ToriiPluginLoader } from '@torii/plugin-core'; +import ToriiDebugPlugin from '@torii/plugin-debug' + +let pluginLoader: ToriiPluginLoader | undefined; + +export function usePlugins(): ToriiPluginLoader { + if (pluginLoader) return pluginLoader; + + pluginLoader = new ToriiPluginLoader(); + pluginLoader.install(ToriiDebugPlugin); + + return pluginLoader; +} diff --git a/torii-client/webapp/src/views/RecentProjectsView.vue b/torii-client/webapp/src/views/RecentProjectsView.vue index cda812e..9af6c25 100644 --- a/torii-client/webapp/src/views/RecentProjectsView.vue +++ b/torii-client/webapp/src/views/RecentProjectsView.vue @@ -47,6 +47,7 @@ import { open } from '@tauri-apps/plugin-dialog'; import { NIcon, NDropdown, DropdownOption } from 'naive-ui'; import { EllipsisVertical } from '@vicons/ionicons5'; import { useRouter } from 'vue-router'; +import { usePlugins } from '@/services/plugins'; const router = useRouter(); const recentProjects = listRecentProjects(); diff --git a/torii-client/webapp/src/views/project/ProjectView.vue b/torii-client/webapp/src/views/project/ProjectView.vue index 337c60b..63067f9 100644 --- a/torii-client/webapp/src/views/project/ProjectView.vue +++ b/torii-client/webapp/src/views/project/ProjectView.vue @@ -114,7 +114,7 @@