@rimori/client 1.0.5 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +13 -0
  2. package/dist/components/MarkdownEditor.js +6 -4
  3. package/dist/components/PluginController.d.ts +21 -0
  4. package/dist/components/PluginController.js +116 -0
  5. package/dist/components/ai/Assistant.js +1 -1
  6. package/dist/components/ai/Avatar.d.ts +5 -3
  7. package/dist/components/ai/Avatar.js +14 -6
  8. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +2 -1
  9. package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +35 -14
  10. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +1 -0
  11. package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +3 -0
  12. package/dist/components/ai/EmbeddedAssistent/TTS/Player.d.ts +2 -0
  13. package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +5 -0
  14. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +3 -0
  15. package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +41 -5
  16. package/dist/components/ai/utils.d.ts +1 -1
  17. package/dist/components.d.ts +1 -0
  18. package/dist/components.js +1 -0
  19. package/dist/controller/AIController.js +2 -1
  20. package/dist/controller/SettingsController.d.ts +15 -15
  21. package/dist/controller/SettingsController.js +15 -16
  22. package/dist/controller/SharedContentController.d.ts +58 -11
  23. package/dist/controller/SharedContentController.js +161 -26
  24. package/dist/controller/SidePluginController.d.ts +1 -12
  25. package/dist/core/components/ContextMenu.d.ts +10 -0
  26. package/dist/core/components/ContextMenu.js +93 -0
  27. package/dist/core.d.ts +2 -0
  28. package/dist/core.js +2 -0
  29. package/dist/hooks/UseChatHook.d.ts +1 -1
  30. package/dist/plugin/AccomplishmentHandler.d.ts +38 -0
  31. package/dist/plugin/AccomplishmentHandler.js +108 -0
  32. package/dist/plugin/ContextMenu.d.ts +17 -0
  33. package/dist/plugin/ContextMenu.js +45 -0
  34. package/dist/plugin/PluginController.js +6 -3
  35. package/dist/plugin/RimoriClient.d.ts +92 -65
  36. package/dist/plugin/RimoriClient.js +105 -75
  37. package/dist/plugin/ThemeSetter.js +2 -2
  38. package/dist/plugin/fromRimori/EventBus.d.ts +6 -3
  39. package/dist/plugin/fromRimori/EventBus.js +15 -9
  40. package/dist/plugin/fromRimori/PluginTypes.d.ts +51 -0
  41. package/dist/plugin/fromRimori/PluginTypes.js +1 -0
  42. package/dist/providers/PluginController.d.ts +21 -0
  43. package/dist/providers/PluginController.js +116 -0
  44. package/dist/providers/PluginProvider.js +26 -73
  45. package/dist/types/Actions.d.ts +4 -0
  46. package/dist/types/Actions.js +1 -0
  47. package/dist/utils/Language.d.ts +66 -0
  48. package/dist/utils/Language.js +67 -0
  49. package/dist/utils/difficultyConverter.d.ts +1 -0
  50. package/dist/utils/difficultyConverter.js +3 -0
  51. package/dist/worker/WorkerSetup.js +4 -4
  52. package/package.json +2 -3
  53. package/src/components/MarkdownEditor.tsx +78 -76
  54. package/src/components/ai/Assistant.tsx +1 -1
  55. package/src/components/ai/Avatar.tsx +65 -48
  56. package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +81 -58
  57. package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +4 -0
  58. package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +6 -0
  59. package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +51 -8
  60. package/src/components/ai/utils.ts +1 -1
  61. package/src/components.ts +2 -1
  62. package/src/controller/AIController.ts +2 -1
  63. package/src/controller/SettingsController.ts +83 -84
  64. package/src/controller/SharedContentController.ts +214 -53
  65. package/src/controller/SidePluginController.ts +1 -13
  66. package/src/core/components/ContextMenu.tsx +123 -0
  67. package/src/core.ts +3 -1
  68. package/src/hooks/UseChatHook.ts +17 -17
  69. package/src/plugin/AccomplishmentHandler.ts +165 -0
  70. package/src/plugin/PluginController.ts +105 -103
  71. package/src/plugin/RimoriClient.ts +267 -250
  72. package/src/plugin/ThemeSetter.ts +2 -2
  73. package/src/plugin/fromRimori/EventBus.ts +23 -12
  74. package/src/plugin/fromRimori/PluginTypes.ts +67 -0
  75. package/src/providers/PluginProvider.tsx +63 -110
  76. package/src/types/Actions.ts +6 -0
  77. package/src/utils/Language.ts +70 -0
  78. package/src/utils/difficultyConverter.ts +4 -0
  79. package/src/worker/WorkerSetup.ts +4 -4
  80. package/dist/components/avatar/Assistant.d.ts +0 -9
  81. package/dist/components/avatar/Assistant.js +0 -59
  82. package/dist/components/avatar/Avatar.d.ts +0 -12
  83. package/dist/components/avatar/Avatar.js +0 -42
  84. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.d.ts +0 -7
  85. package/dist/components/avatar/EmbeddedAssistent/AudioInputField.js +0 -38
  86. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.d.ts +0 -7
  87. package/dist/components/avatar/EmbeddedAssistent/CircleAudioAvatar.js +0 -59
  88. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.d.ts +0 -19
  89. package/dist/components/avatar/EmbeddedAssistent/TTS/MessageSender.js +0 -84
  90. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.d.ts +0 -25
  91. package/dist/components/avatar/EmbeddedAssistent/TTS/Player.js +0 -180
  92. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.d.ts +0 -7
  93. package/dist/components/avatar/EmbeddedAssistent/VoiceRecoder.js +0 -45
  94. package/dist/components/avatar/utils.d.ts +0 -6
  95. package/dist/components/avatar/utils.js +0 -14
@@ -0,0 +1,21 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js';
2
+ import { RimoriClient } from "../plugin/RimoriClient";
3
+ export declare class PluginController {
4
+ private static client;
5
+ private static instance;
6
+ private communicationSecret;
7
+ private supabase;
8
+ private supabaseInfo;
9
+ private pluginId;
10
+ private constructor();
11
+ static getInstance(sender: string): Promise<RimoriClient>;
12
+ private getSecret;
13
+ getClient(): Promise<{
14
+ supabase: SupabaseClient;
15
+ tablePrefix: string;
16
+ pluginId: string;
17
+ }>;
18
+ getToken(): Promise<string>;
19
+ getSupabaseUrl(): string;
20
+ getGlobalEventTopic(preliminaryTopic: string): string;
21
+ }
@@ -0,0 +1,116 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { createClient } from '@supabase/supabase-js';
11
+ import { EventBus } from '../plugin/fromRimori/EventBus';
12
+ import { RimoriClient } from "../plugin/RimoriClient";
13
+ import { setTheme } from '../plugin/ThemeSetter';
14
+ export class PluginController {
15
+ constructor(pluginId) {
16
+ this.communicationSecret = null;
17
+ this.supabase = null;
18
+ this.supabaseInfo = null;
19
+ this.pluginId = pluginId;
20
+ this.getClient = this.getClient.bind(this);
21
+ if (typeof WorkerGlobalScope === 'undefined') {
22
+ setTheme();
23
+ }
24
+ window.addEventListener("message", (event) => {
25
+ // console.log("client: message received", event);
26
+ const { topic, sender, data, eventId } = event.data.event;
27
+ // skip forwarding messages from own plugin
28
+ if (sender === pluginId)
29
+ return;
30
+ EventBus.emit(sender, topic, data, eventId);
31
+ });
32
+ EventBus.on("*", (event) => {
33
+ // skip messages which are not from the own plugin
34
+ if (event.sender !== this.pluginId)
35
+ return;
36
+ if (event.topic.startsWith("self."))
37
+ return;
38
+ window.parent.postMessage({ event, secret: this.getSecret() }, "*");
39
+ });
40
+ }
41
+ static getInstance(sender) {
42
+ return __awaiter(this, void 0, void 0, function* () {
43
+ if (!PluginController.instance) {
44
+ PluginController.instance = new PluginController(sender);
45
+ PluginController.client = yield RimoriClient.getInstance(PluginController.instance);
46
+ }
47
+ return PluginController.client;
48
+ });
49
+ }
50
+ getSecret() {
51
+ if (!this.communicationSecret) {
52
+ const secret = new URLSearchParams(window.location.search).get("secret");
53
+ if (!secret) {
54
+ throw new Error("Communication secret not found in URL as query parameter");
55
+ }
56
+ this.communicationSecret = secret;
57
+ }
58
+ return this.communicationSecret;
59
+ }
60
+ getClient() {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ if (this.supabase &&
63
+ this.supabaseInfo &&
64
+ this.supabaseInfo.expiration > new Date()) {
65
+ return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
66
+ }
67
+ const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
68
+ this.supabaseInfo = data;
69
+ this.supabase = createClient(this.supabaseInfo.url, this.supabaseInfo.key, {
70
+ accessToken: () => Promise.resolve(this.getToken())
71
+ });
72
+ return { supabase: this.supabase, tablePrefix: this.supabaseInfo.tablePrefix, pluginId: this.supabaseInfo.pluginId };
73
+ });
74
+ }
75
+ getToken() {
76
+ return __awaiter(this, void 0, void 0, function* () {
77
+ if (this.supabaseInfo && this.supabaseInfo.expiration && this.supabaseInfo.expiration > new Date()) {
78
+ return this.supabaseInfo.token;
79
+ }
80
+ const { data } = yield EventBus.request(this.pluginId, "global.supabase.requestAccess");
81
+ if (!this.supabaseInfo) {
82
+ throw new Error("Supabase info not found");
83
+ }
84
+ this.supabaseInfo.token = data.token;
85
+ this.supabaseInfo.expiration = data.expiration;
86
+ return this.supabaseInfo.token;
87
+ });
88
+ }
89
+ getSupabaseUrl() {
90
+ if (!this.supabaseInfo) {
91
+ throw new Error("Supabase info not found");
92
+ }
93
+ return this.supabaseInfo.url;
94
+ }
95
+ getGlobalEventTopic(preliminaryTopic) {
96
+ var _a, _b;
97
+ if (preliminaryTopic.startsWith("global.")) {
98
+ return preliminaryTopic;
99
+ }
100
+ if (preliminaryTopic.startsWith("self.")) {
101
+ return preliminaryTopic;
102
+ }
103
+ const topicParts = preliminaryTopic.split(".");
104
+ if (topicParts.length === 3) {
105
+ if (!topicParts[0].startsWith("pl") && topicParts[0] !== "global") {
106
+ throw new Error("The event topic must start with the plugin id or 'global'.");
107
+ }
108
+ return preliminaryTopic;
109
+ }
110
+ else if (topicParts.length > 3) {
111
+ throw new Error(`The event topic must consist of 3 parts. <pluginId>.<topic area>.<action>. Received: ${preliminaryTopic}`);
112
+ }
113
+ const topicRoot = (_b = (_a = this.supabaseInfo) === null || _a === void 0 ? void 0 : _a.pluginId) !== null && _b !== void 0 ? _b : "global";
114
+ return `${topicRoot}.${preliminaryTopic}`;
115
+ }
116
+ }
@@ -1,33 +1,34 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { createContext, useContext, useEffect, useState } from 'react';
3
3
  import { PluginController } from '../plugin/PluginController';
4
4
  import { EventBusHandler } from '../plugin/fromRimori/EventBus';
5
- EventBusHandler.getInstance("Plugin EventBus");
5
+ import ContextMenu from '../core/components/ContextMenu';
6
6
  const PluginContext = createContext(null);
7
7
  export const PluginProvider = ({ children, pluginId }) => {
8
8
  const [plugin, setPlugin] = useState(null);
9
- const [contextMenuOnSelect, setContextMenuOnTextSelection] = useState(false);
10
- //route change
9
+ initEventBus(pluginId);
11
10
  useEffect(() => {
12
- let lastHash = window.location.hash;
13
- setInterval(() => {
14
- if (lastHash !== window.location.hash) {
15
- lastHash = window.location.hash;
16
- console.log('url changed:', lastHash);
17
- plugin === null || plugin === void 0 ? void 0 : plugin.event.emit('session.triggerUrlChange', window.location.hash);
18
- }
19
- }, 100);
20
11
  PluginController.getInstance(pluginId).then(setPlugin);
21
- }, []);
22
- //check if context menu opens on text selection
12
+ }, [pluginId]);
13
+ //route change
23
14
  useEffect(() => {
24
15
  if (!plugin)
25
16
  return;
26
- plugin.plugin.getUserInfo().then((userInfo) => {
27
- setContextMenuOnTextSelection(userInfo.contextMenuOnSelect);
28
- }).catch(error => {
29
- console.error('Error fetching settings:', error);
30
- });
17
+ const url = new URL(window.location.href);
18
+ //sidebar pages should not report url changes
19
+ if (url.searchParams.get("applicationMode") === "sidebar")
20
+ return;
21
+ let lastHash = url.hash;
22
+ const emitUrlChange = (url) => plugin.event.emit('session.triggerUrlChange', { url });
23
+ const interval = setInterval(() => {
24
+ if (lastHash === window.location.hash)
25
+ return;
26
+ lastHash = window.location.hash;
27
+ // console.log('url changed:', lastHash);
28
+ emitUrlChange(lastHash);
29
+ }, 1000);
30
+ emitUrlChange(lastHash);
31
+ return () => clearInterval(interval);
31
32
  }, [plugin]);
32
33
  //detect page height change
33
34
  useEffect(() => {
@@ -37,63 +38,10 @@ export const PluginProvider = ({ children, pluginId }) => {
37
38
  handleResize();
38
39
  return () => body.removeEventListener('resize', handleResize);
39
40
  }, [plugin]);
40
- //context menu
41
- useEffect(() => {
42
- let lastMouseX = 0;
43
- let lastMouseY = 0;
44
- let isSelecting = false;
45
- // Track mouse position
46
- const handleMouseMove = (e) => {
47
- lastMouseX = e.clientX;
48
- lastMouseY = e.clientY;
49
- };
50
- const handleContextMenu = (e) => {
51
- var _a;
52
- const selection = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString().trim();
53
- if (selection) {
54
- e.preventDefault();
55
- // console.log('context menu handled', selection);
56
- plugin === null || plugin === void 0 ? void 0 : plugin.event.emit('global.contextMenu.trigger', { text: selection, x: e.clientX, y: e.clientY, open: true });
57
- }
58
- };
59
- const handleSelectionChange = () => {
60
- var _a;
61
- // if (triggerOnTextSelection) {
62
- const selection = (_a = window.getSelection()) === null || _a === void 0 ? void 0 : _a.toString().trim();
63
- const open = !!selection && isSelecting;
64
- // console.log('Selection change, contextMenuOnSelect:', contextMenuOnSelect);
65
- plugin === null || plugin === void 0 ? void 0 : plugin.event.emit('global.contextMenu.trigger', { text: selection, x: lastMouseX, y: lastMouseY, open });
66
- // }
67
- };
68
- const handleMouseUpDown = (e) => {
69
- if (e.type === 'mousedown') {
70
- isSelecting = false;
71
- }
72
- else if (e.type === 'mouseup') {
73
- isSelecting = true;
74
- // console.log('mouseup, contextMenuOnSelect:', contextMenuOnSelect);
75
- if (contextMenuOnSelect) {
76
- handleSelectionChange();
77
- }
78
- }
79
- };
80
- document.addEventListener('contextmenu', handleContextMenu);
81
- document.addEventListener('selectionchange', handleSelectionChange);
82
- document.addEventListener("mousemove", handleMouseMove);
83
- document.addEventListener('mousedown', handleMouseUpDown);
84
- document.addEventListener('mouseup', handleMouseUpDown);
85
- return () => {
86
- document.removeEventListener("mousemove", handleMouseMove);
87
- document.removeEventListener('contextmenu', handleContextMenu);
88
- document.removeEventListener('selectionchange', handleSelectionChange);
89
- document.removeEventListener('mousedown', handleMouseUpDown);
90
- document.removeEventListener('mouseup', handleMouseUpDown);
91
- };
92
- }, [plugin, contextMenuOnSelect]);
93
41
  if (!plugin) {
94
42
  return "";
95
43
  }
96
- return (_jsx(PluginContext.Provider, { value: plugin, children: children }));
44
+ return (_jsxs(PluginContext.Provider, { value: plugin, children: [_jsx(ContextMenu, { client: plugin }), children] }));
97
45
  };
98
46
  export const usePlugin = () => {
99
47
  const context = useContext(PluginContext);
@@ -102,3 +50,8 @@ export const usePlugin = () => {
102
50
  }
103
51
  return context;
104
52
  };
53
+ function initEventBus(pluginId) {
54
+ const url = new URL(window.location.href);
55
+ const isSidebar = url.searchParams.get("applicationMode") === "sidebar";
56
+ EventBusHandler.getInstance("Plugin EventBus " + pluginId + " " + (isSidebar ? "sidebar" : "main"));
57
+ }
@@ -0,0 +1,4 @@
1
+ export type MainPanelAction = {
2
+ pluginId: string;
3
+ actionKey: string;
4
+ } & Record<string, string>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,66 @@
1
+ export declare const languageKeys: {
2
+ readonly sq: "albanian";
3
+ readonly ar: "arabic";
4
+ readonly hy: "armenian";
5
+ readonly az: "azerbaijani";
6
+ readonly bn: "bengali";
7
+ readonly bs: "bosnian";
8
+ readonly bg: "bulgarian";
9
+ readonly ca: "catalan";
10
+ readonly zh: "chinese";
11
+ readonly hr: "croatian";
12
+ readonly cs: "czech";
13
+ readonly da: "danish";
14
+ readonly nl: "dutch";
15
+ readonly en: "english";
16
+ readonly et: "estonian";
17
+ readonly fi: "finnish";
18
+ readonly fr: "french";
19
+ readonly gl: "galician";
20
+ readonly de: "german";
21
+ readonly el: "greek";
22
+ readonly he: "hebrew";
23
+ readonly hi: "hindi";
24
+ readonly hu: "hungarian";
25
+ readonly is: "icelandic";
26
+ readonly id: "indonesian";
27
+ readonly it: "italian";
28
+ readonly ja: "japanese";
29
+ readonly kn: "kannada";
30
+ readonly kk: "kazakh";
31
+ readonly ko: "korean";
32
+ readonly lv: "latvian";
33
+ readonly lt: "lithuanian";
34
+ readonly mk: "macedonian";
35
+ readonly ms: "malay";
36
+ readonly mr: "marathi";
37
+ readonly mi: "maori";
38
+ readonly ne: "nepali";
39
+ readonly no: "norwegian";
40
+ readonly fa: "persian";
41
+ readonly pl: "polish";
42
+ readonly pt: "portuguese";
43
+ readonly ro: "romanian";
44
+ readonly ru: "russian";
45
+ readonly sr: "serbian";
46
+ readonly sk: "slovak";
47
+ readonly sl: "slovenian";
48
+ readonly es: "spanish";
49
+ readonly sw: "swahili";
50
+ readonly sv: "swedish";
51
+ readonly tl: "filipino";
52
+ readonly ta: "tamil";
53
+ readonly th: "thai";
54
+ readonly tr: "turkish";
55
+ readonly uk: "ukrainian";
56
+ readonly ur: "urdu";
57
+ readonly vi: "vietnamese";
58
+ readonly cy: "welsh";
59
+ };
60
+ export type Language = keyof typeof languageKeys;
61
+ /**
62
+ * Get the language name from the language code
63
+ * @param languageCode The code of the language
64
+ * @returns The language name
65
+ */
66
+ export declare function getLanguageName(languageCode: Language): string;
@@ -0,0 +1,67 @@
1
+ export const languageKeys = {
2
+ sq: "albanian",
3
+ ar: "arabic",
4
+ hy: "armenian",
5
+ az: "azerbaijani",
6
+ bn: "bengali",
7
+ bs: "bosnian",
8
+ bg: "bulgarian",
9
+ ca: "catalan",
10
+ zh: "chinese",
11
+ hr: "croatian",
12
+ cs: "czech",
13
+ da: "danish",
14
+ nl: "dutch",
15
+ en: "english",
16
+ et: "estonian",
17
+ fi: "finnish",
18
+ fr: "french",
19
+ gl: "galician",
20
+ de: "german",
21
+ el: "greek",
22
+ he: "hebrew",
23
+ hi: "hindi",
24
+ hu: "hungarian",
25
+ is: "icelandic",
26
+ id: "indonesian",
27
+ it: "italian",
28
+ ja: "japanese",
29
+ kn: "kannada",
30
+ kk: "kazakh",
31
+ ko: "korean",
32
+ lv: "latvian",
33
+ lt: "lithuanian",
34
+ mk: "macedonian",
35
+ ms: "malay",
36
+ mr: "marathi",
37
+ mi: "maori",
38
+ ne: "nepali",
39
+ no: "norwegian",
40
+ fa: "persian",
41
+ pl: "polish",
42
+ pt: "portuguese",
43
+ ro: "romanian",
44
+ ru: "russian",
45
+ sr: "serbian",
46
+ sk: "slovak",
47
+ sl: "slovenian",
48
+ es: "spanish",
49
+ sw: "swahili",
50
+ sv: "swedish",
51
+ tl: "filipino",
52
+ ta: "tamil",
53
+ th: "thai",
54
+ tr: "turkish",
55
+ uk: "ukrainian",
56
+ ur: "urdu",
57
+ vi: "vietnamese",
58
+ cy: "welsh"
59
+ };
60
+ /**
61
+ * Get the language name from the language code
62
+ * @param languageCode The code of the language
63
+ * @returns The language name
64
+ */
65
+ export function getLanguageName(languageCode) {
66
+ return languageKeys[languageCode];
67
+ }
@@ -1,3 +1,4 @@
1
1
  export type LanguageLevel = "Pre-A1" | "A1" | "A2" | "B1" | "B2" | "C1" | "C2" | "Post-C2";
2
2
  export declare function getDifficultyLevel(difficulty: LanguageLevel): number;
3
3
  export declare function getDifficultyLabel(difficulty: number): LanguageLevel;
4
+ export declare function getNeighborDifficultyLevel(difficulty: LanguageLevel, difficultyAdjustment: number): LanguageLevel;
@@ -5,3 +5,6 @@ export function getDifficultyLevel(difficulty) {
5
5
  export function getDifficultyLabel(difficulty) {
6
6
  return codes[difficulty];
7
7
  }
8
+ export function getNeighborDifficultyLevel(difficulty, difficultyAdjustment) {
9
+ return getDifficultyLabel(getDifficultyLevel(difficulty) + difficultyAdjustment);
10
+ }
@@ -25,7 +25,7 @@ export function setupWorker(init) {
25
25
  postMessage: (message) => {
26
26
  message.event.sender = "worker." + message.event.sender;
27
27
  checkDebugMode(message.event);
28
- logIfDebug('[Worker] sending event to Rimori', message.event);
28
+ logIfDebug('sending event to Rimori', message.event);
29
29
  self.postMessage(message);
30
30
  }
31
31
  },
@@ -43,16 +43,16 @@ export function setupWorker(init) {
43
43
  // Handle init message from Rimori.
44
44
  self.onmessage = (response) => __awaiter(this, void 0, void 0, function* () {
45
45
  checkDebugMode(response.data);
46
- logIfDebug('[Worker] message received', response.data);
46
+ logIfDebug('Message received', response.data);
47
47
  const event = response.data;
48
48
  if (event.topic === 'global.worker.requestInit') {
49
49
  if (!controller) {
50
50
  mockWindow.APP_CONFIG.SUPABASE_URL = event.data.supabaseUrl;
51
51
  mockWindow.APP_CONFIG.SUPABASE_ANON_KEY = event.data.supabaseAnonKey;
52
52
  controller = yield PluginController.getInstance(event.data.pluginId);
53
- logIfDebug('[Worker] Worker initialized.');
53
+ logIfDebug('Worker initialized.');
54
54
  yield init(controller);
55
- logIfDebug('[Worker] Plugin listeners initialized.');
55
+ logIfDebug('Plugin listeners initialized.');
56
56
  }
57
57
  const initEvent = {
58
58
  timestamp: new Date().toISOString(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rimori/client",
3
- "version": "1.0.5",
3
+ "version": "1.1.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "exports": {
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsc && sass src/style.scss:dist/style.css",
22
- "dev": "tsc -w",
22
+ "dev": "tsc -w --preserveWatchOutput",
23
23
  "css-dev": "sass --watch src/style.scss:dist/style.css"
24
24
  },
25
25
  "peerDependencies": {
@@ -30,7 +30,6 @@
30
30
  "@supabase/supabase-js": "^2.48.1",
31
31
  "@tiptap/react": "2.10.3",
32
32
  "@tiptap/starter-kit": "2.10.3",
33
- "uuid": "11.1.0",
34
33
  "react-icons": "^5.4.0",
35
34
  "react-markdown": "^10.1.0",
36
35
  "tiptap-markdown": "^0.8.10",
@@ -11,101 +11,103 @@ import { FaBold, FaCode, FaItalic, FaParagraph, FaStrikethrough } from "react-ic
11
11
  // This inplementation is rooted in the Tiptap editor basic example https://codesandbox.io/p/devbox/editor-9x9dkd
12
12
 
13
13
  interface EditorButtonProps {
14
- action: string;
15
- isActive?: boolean;
16
- label: string | React.ReactNode;
17
- disabled?: boolean;
14
+ action: string;
15
+ isActive?: boolean;
16
+ label: string | React.ReactNode;
17
+ disabled?: boolean;
18
18
  }
19
19
 
20
20
  const EditorButton = ({ action, isActive, label, disabled }: EditorButtonProps) => {
21
- const { editor } = useCurrentEditor() as any;
21
+ const { editor } = useCurrentEditor() as any;
22
22
 
23
- if (!editor) {
24
- return null;
25
- }
26
-
27
- if (action.includes("heading")) {
28
- const level = parseInt(action[action.length - 1]);
29
- return (
30
- <button
31
- onClick={() => editor.chain().focus().toggleHeading({ level: level }).run()}
32
- className={`pl-2 ${isActive ? "is-active" : ""}`}
33
- >
34
- {label}
35
- </button>
36
- );
37
- }
23
+ if (!editor) {
24
+ return null;
25
+ }
38
26
 
27
+ if (action.includes("heading")) {
28
+ const level = parseInt(action[action.length - 1]);
39
29
  return (
40
- <button
41
- onClick={() => editor.chain().focus()[action]().run()}
42
- disabled={disabled ? !editor.can().chain().focus()[action]().run() : false}
43
- className={`pl-2 ${isActive ? "is-active" : ""}`}
44
- >
45
- {label}
46
- </button>
30
+ <button
31
+ onClick={() => editor.chain().focus().toggleHeading({ level: level }).run()}
32
+ className={`pl-2 ${isActive ? "is-active" : ""}`}
33
+ >
34
+ {label}
35
+ </button>
47
36
  );
37
+ }
38
+
39
+ return (
40
+ <button
41
+ onClick={() => editor.chain().focus()[action]().run()}
42
+ disabled={disabled ? !editor.can().chain().focus()[action]().run() : false}
43
+ className={`pl-2 ${isActive ? "is-active" : ""}`}
44
+ >
45
+ {label}
46
+ </button>
47
+ );
48
48
  };
49
49
 
50
50
  const MenuBar = () => {
51
- const { editor } = useCurrentEditor();
51
+ const { editor } = useCurrentEditor();
52
52
 
53
- if (!editor) {
54
- return null;
55
- }
53
+ if (!editor) {
54
+ return null;
55
+ }
56
56
 
57
- return (
58
- <div className="bg-gray-400 dark:bg-gray-800 dark:text-white text-lg flex flex-row flex-wrap items-center p-1">
59
- <EditorButton action="toggleBold" isActive={editor.isActive("bold")} label={<FaBold />} disabled />
60
- <EditorButton action="toggleItalic" isActive={editor.isActive("italic")} label={<FaItalic />} disabled />
61
- <EditorButton action="toggleStrike" isActive={editor.isActive("strike")} label={<FaStrikethrough />} disabled />
62
- <EditorButton action="toggleCode" isActive={editor.isActive("code")} label={<FaCode />} disabled />
63
- <EditorButton action="setParagraph" isActive={editor.isActive("paragraph")} label={<FaParagraph />} />
64
- <EditorButton action='setHeading1' isActive={editor.isActive("heading", { level: 1 })} label={<LuHeading1 size={"24px"} />} />
65
- <EditorButton action='setHeading2' isActive={editor.isActive("heading", { level: 2 })} label={<LuHeading2 size={"24px"} />} />
66
- <EditorButton action='setHeading3' isActive={editor.isActive("heading", { level: 3 })} label={<LuHeading3 size={"24px"} />} />
67
- <EditorButton action="toggleBulletList" isActive={editor.isActive("bulletList")} label={<AiOutlineUnorderedList size={"24px"} />} />
68
- <EditorButton action="toggleOrderedList" isActive={editor.isActive("orderedList")} label={<GoListOrdered size={"24px"} />} />
69
- <EditorButton action="toggleCodeBlock" isActive={editor.isActive("codeBlock")} label={<PiCodeBlock size={"24px"} />} />
70
- <EditorButton action="toggleBlockquote" isActive={editor.isActive("blockquote")} label={<TbBlockquote size={"24px"} />} />
71
- </div>
72
- );
57
+ return (
58
+ <div className="bg-gray-400 dark:bg-gray-800 dark:text-white text-lg flex flex-row flex-wrap items-center p-1">
59
+ <EditorButton action="toggleBold" isActive={editor.isActive("bold")} label={<FaBold />} disabled />
60
+ <EditorButton action="toggleItalic" isActive={editor.isActive("italic")} label={<FaItalic />} disabled />
61
+ <EditorButton action="toggleStrike" isActive={editor.isActive("strike")} label={<FaStrikethrough />} disabled />
62
+ <EditorButton action="toggleCode" isActive={editor.isActive("code")} label={<FaCode />} disabled />
63
+ <EditorButton action="setParagraph" isActive={editor.isActive("paragraph")} label={<FaParagraph />} />
64
+ <EditorButton action='setHeading1' isActive={editor.isActive("heading", { level: 1 })} label={<LuHeading1 size={"24px"} />} />
65
+ <EditorButton action='setHeading2' isActive={editor.isActive("heading", { level: 2 })} label={<LuHeading2 size={"24px"} />} />
66
+ <EditorButton action='setHeading3' isActive={editor.isActive("heading", { level: 3 })} label={<LuHeading3 size={"24px"} />} />
67
+ <EditorButton action="toggleBulletList" isActive={editor.isActive("bulletList")} label={<AiOutlineUnorderedList size={"24px"} />} />
68
+ <EditorButton action="toggleOrderedList" isActive={editor.isActive("orderedList")} label={<GoListOrdered size={"24px"} />} />
69
+ <EditorButton action="toggleCodeBlock" isActive={editor.isActive("codeBlock")} label={<PiCodeBlock size={"24px"} />} />
70
+ <EditorButton action="toggleBlockquote" isActive={editor.isActive("blockquote")} label={<TbBlockquote size={"24px"} />} />
71
+ </div>
72
+ );
73
73
  };
74
74
 
75
75
  const extensions = [
76
- StarterKit.configure({
77
- bulletList: {
78
- keepMarks: true,
79
- keepAttributes: false,
80
- },
81
- orderedList: {
82
- keepMarks: true,
83
- keepAttributes: false,
84
- },
85
- }),
86
- Markdown,
76
+ StarterKit.configure({
77
+ bulletList: {
78
+ HTMLAttributes: {
79
+ class: "list-disc list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0",
80
+ },
81
+ },
82
+ orderedList: {
83
+ HTMLAttributes: {
84
+ className: "list-decimal list-inside dark:text-white p-1 mt-1 [&_li]:mb-1 [&_p]:inline m-0",
85
+ },
86
+ },
87
+ }),
88
+ Markdown,
87
89
  ];
88
90
 
89
91
  interface Props {
90
- content?: string;
91
- editable: boolean;
92
- className?: string;
93
- onUpdate?: (content: string) => void;
92
+ content?: string;
93
+ editable: boolean;
94
+ className?: string;
95
+ onUpdate?: (content: string) => void;
94
96
  }
95
97
 
96
98
  export const MarkdownEditor = (props: Props) => {
97
- return (
98
- <div className={"text-md border border-gray-800 overflow-hidden " + props.className} style={{ borderWidth: props.editable ? 1 : 0 }}>
99
- <EditorProvider
100
- key={(props.editable ? "editable" : "readonly") + props.content}
101
- slotBefore={props.editable ? <MenuBar /> : null}
102
- extensions={extensions}
103
- content={props.content}
104
- editable={props.editable}
105
- onUpdate={(e) => {
106
- props.onUpdate && props.onUpdate(e.editor.storage.markdown.getMarkdown());
107
- }}
108
- ></EditorProvider>
109
- </div>
110
- );
99
+ return (
100
+ <div className={"text-md border border-gray-800 overflow-hidden " + props.className} style={{ borderWidth: props.editable ? 1 : 0 }}>
101
+ <EditorProvider
102
+ key={(props.editable ? "editable" : "readonly") + props.content}
103
+ slotBefore={props.editable ? <MenuBar /> : null}
104
+ extensions={extensions}
105
+ content={props.content}
106
+ editable={props.editable}
107
+ onUpdate={(e) => {
108
+ props.onUpdate && props.onUpdate(e.editor.storage.markdown.getMarkdown());
109
+ }}
110
+ ></EditorProvider>
111
+ </div>
112
+ );
111
113
  };