@rimori/react-client 0.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.
- package/.prettierignore +35 -0
- package/LICENSE +201 -0
- package/README copy.md +1216 -0
- package/README.md +1 -0
- package/dist/components/MarkdownEditor.d.ts +8 -0
- package/dist/components/MarkdownEditor.js +48 -0
- package/dist/components/Spinner.d.ts +8 -0
- package/dist/components/Spinner.js +4 -0
- package/dist/components/ai/Assistant.d.ts +9 -0
- package/dist/components/ai/Assistant.js +58 -0
- package/dist/components/ai/Avatar.d.ts +14 -0
- package/dist/components/ai/Avatar.js +59 -0
- package/dist/components/ai/EmbeddedAssistent/AudioInputField.d.ts +7 -0
- package/dist/components/ai/EmbeddedAssistent/AudioInputField.js +37 -0
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +8 -0
- package/dist/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +79 -0
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +19 -0
- package/dist/components/ai/EmbeddedAssistent/TTS/MessageSender.js +91 -0
- package/dist/components/ai/EmbeddedAssistent/TTS/Player.d.ts +27 -0
- package/dist/components/ai/EmbeddedAssistent/TTS/Player.js +185 -0
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +11 -0
- package/dist/components/ai/EmbeddedAssistent/VoiceRecoder.js +95 -0
- package/dist/components/ai/utils.d.ts +6 -0
- package/dist/components/ai/utils.js +13 -0
- package/dist/components/audio/Playbutton.d.ts +15 -0
- package/dist/components/audio/Playbutton.js +80 -0
- package/dist/components/components/ContextMenu.d.ts +10 -0
- package/dist/components/components/ContextMenu.js +135 -0
- package/dist/hooks/I18nHooks.d.ts +11 -0
- package/dist/hooks/I18nHooks.js +25 -0
- package/dist/hooks/UseChatHook.d.ts +10 -0
- package/dist/hooks/UseChatHook.js +29 -0
- package/dist/providers/PluginProvider.d.ts +11 -0
- package/dist/providers/PluginProvider.js +142 -0
- package/dist/react-client/plugin/ThemeSetter.d.ts +2 -0
- package/dist/react-client/plugin/ThemeSetter.js +19 -0
- package/dist/react-client/src/components/ContextMenu.d.ts +10 -0
- package/dist/react-client/src/components/ContextMenu.js +135 -0
- package/dist/react-client/src/components/MarkdownEditor.d.ts +8 -0
- package/dist/react-client/src/components/MarkdownEditor.js +48 -0
- package/dist/react-client/src/components/Spinner.d.ts +8 -0
- package/dist/react-client/src/components/Spinner.js +4 -0
- package/dist/react-client/src/components/ai/Assistant.d.ts +9 -0
- package/dist/react-client/src/components/ai/Assistant.js +58 -0
- package/dist/react-client/src/components/ai/Avatar.d.ts +14 -0
- package/dist/react-client/src/components/ai/Avatar.js +59 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/AudioInputField.d.ts +7 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/AudioInputField.js +37 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.d.ts +8 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.js +79 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/TTS/MessageSender.d.ts +19 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/TTS/MessageSender.js +91 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/TTS/Player.d.ts +27 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/TTS/Player.js +185 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/VoiceRecoder.d.ts +11 -0
- package/dist/react-client/src/components/ai/EmbeddedAssistent/VoiceRecoder.js +95 -0
- package/dist/react-client/src/components/ai/utils.d.ts +6 -0
- package/dist/react-client/src/components/ai/utils.js +13 -0
- package/dist/react-client/src/components/audio/Playbutton.d.ts +15 -0
- package/dist/react-client/src/components/audio/Playbutton.js +82 -0
- package/dist/react-client/src/components/components/ContextMenu.d.ts +10 -0
- package/dist/react-client/src/components/components/ContextMenu.js +135 -0
- package/dist/react-client/src/hooks/I18nHooks.d.ts +11 -0
- package/dist/react-client/src/hooks/I18nHooks.js +25 -0
- package/dist/react-client/src/hooks/UseChatHook.d.ts +10 -0
- package/dist/react-client/src/hooks/UseChatHook.js +29 -0
- package/dist/react-client/src/plugin/ThemeSetter.d.ts +2 -0
- package/dist/react-client/src/plugin/ThemeSetter.js +19 -0
- package/dist/react-client/src/providers/PluginProvider.d.ts +12 -0
- package/dist/react-client/src/providers/PluginProvider.js +142 -0
- package/dist/react-client/src/utils/FullscreenUtils.d.ts +2 -0
- package/dist/react-client/src/utils/FullscreenUtils.js +23 -0
- package/dist/react-client/src/utils/PluginUtils.d.ts +2 -0
- package/dist/react-client/src/utils/PluginUtils.js +23 -0
- package/dist/rimori-client/src/cli/types/DatabaseTypes.d.ts +103 -0
- package/dist/rimori-client/src/cli/types/DatabaseTypes.js +2 -0
- package/dist/rimori-client/src/controller/AIController.d.ts +15 -0
- package/dist/rimori-client/src/controller/AIController.js +255 -0
- package/dist/rimori-client/src/controller/AccomplishmentController.d.ts +38 -0
- package/dist/rimori-client/src/controller/AccomplishmentController.js +112 -0
- package/dist/rimori-client/src/controller/AudioController.d.ts +37 -0
- package/dist/rimori-client/src/controller/AudioController.js +68 -0
- package/dist/rimori-client/src/controller/ExerciseController.d.ts +54 -0
- package/dist/rimori-client/src/controller/ExerciseController.js +74 -0
- package/dist/rimori-client/src/controller/ObjectController.d.ts +42 -0
- package/dist/rimori-client/src/controller/ObjectController.js +76 -0
- package/dist/rimori-client/src/controller/SettingsController.d.ts +79 -0
- package/dist/rimori-client/src/controller/SettingsController.js +118 -0
- package/dist/rimori-client/src/controller/SharedContentController.d.ts +106 -0
- package/dist/rimori-client/src/controller/SharedContentController.js +285 -0
- package/dist/rimori-client/src/controller/TranslationController.d.ts +38 -0
- package/dist/rimori-client/src/controller/TranslationController.js +106 -0
- package/dist/rimori-client/src/controller/VoiceController.d.ts +9 -0
- package/dist/rimori-client/src/controller/VoiceController.js +37 -0
- package/dist/rimori-client/src/fromRimori/EventBus.d.ts +101 -0
- package/dist/rimori-client/src/fromRimori/EventBus.js +263 -0
- package/dist/rimori-client/src/fromRimori/PluginTypes.d.ts +174 -0
- package/dist/rimori-client/src/fromRimori/PluginTypes.js +1 -0
- package/dist/rimori-client/src/index.d.ts +11 -0
- package/dist/rimori-client/src/index.js +10 -0
- package/dist/rimori-client/src/plugin/CommunicationHandler.d.ts +48 -0
- package/dist/rimori-client/src/plugin/CommunicationHandler.js +234 -0
- package/dist/rimori-client/src/plugin/Logger.d.ts +73 -0
- package/dist/rimori-client/src/plugin/Logger.js +308 -0
- package/dist/rimori-client/src/plugin/RimoriClient.d.ts +258 -0
- package/dist/rimori-client/src/plugin/RimoriClient.js +375 -0
- package/dist/rimori-client/src/plugin/StandaloneClient.d.ts +17 -0
- package/dist/rimori-client/src/plugin/StandaloneClient.js +115 -0
- package/dist/rimori-client/src/utils/difficultyConverter.d.ts +4 -0
- package/dist/rimori-client/src/utils/difficultyConverter.js +10 -0
- package/dist/rimori-client/src/utils/endpoint.d.ts +2 -0
- package/dist/rimori-client/src/utils/endpoint.js +2 -0
- package/dist/style.css +110 -0
- package/dist/style.css.map +1 -0
- package/dist/utils/PluginUtils.d.ts +2 -0
- package/dist/utils/PluginUtils.js +23 -0
- package/eslint.config.js +53 -0
- package/index.ts +6 -0
- package/package.json +47 -0
- package/prettier.config.js +8 -0
- package/src/components/ContextMenu.tsx +177 -0
- package/src/components/MarkdownEditor.tsx +144 -0
- package/src/components/Spinner.tsx +29 -0
- package/src/components/ai/Assistant.tsx +96 -0
- package/src/components/ai/Avatar.tsx +99 -0
- package/src/components/ai/EmbeddedAssistent/AudioInputField.tsx +73 -0
- package/src/components/ai/EmbeddedAssistent/CircleAudioAvatar.tsx +107 -0
- package/src/components/ai/EmbeddedAssistent/TTS/MessageSender.ts +96 -0
- package/src/components/ai/EmbeddedAssistent/TTS/Player.ts +197 -0
- package/src/components/ai/EmbeddedAssistent/VoiceRecoder.tsx +129 -0
- package/src/components/ai/utils.ts +21 -0
- package/src/components/audio/Playbutton.tsx +126 -0
- package/src/hooks/I18nHooks.ts +33 -0
- package/src/hooks/UseChatHook.ts +38 -0
- package/src/plugin/ThemeSetter.ts +23 -0
- package/src/providers/PluginProvider.tsx +197 -0
- package/src/style.scss +136 -0
- package/src/utils/FullscreenUtils.ts +22 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import React, { createContext, useContext, ReactNode, useEffect, useState } from 'react';
|
|
2
|
+
import { EventBusHandler, RimoriClient, StandaloneClient } from '@rimori/client';
|
|
3
|
+
import ContextMenu from '../components/ContextMenu';
|
|
4
|
+
|
|
5
|
+
interface PluginProviderProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
pluginId: string;
|
|
8
|
+
settings?: {
|
|
9
|
+
disableContextMenu?: boolean;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const PluginContext = createContext<RimoriClient | null>(null);
|
|
14
|
+
|
|
15
|
+
export const PluginProvider: React.FC<PluginProviderProps> = ({ children, pluginId, settings }) => {
|
|
16
|
+
const [plugin, setPlugin] = useState<RimoriClient | null>(null);
|
|
17
|
+
const [standaloneClient, setStandaloneClient] = useState<StandaloneClient | boolean>(false);
|
|
18
|
+
const [applicationMode, setApplicationMode] = useState<string | null>(null);
|
|
19
|
+
const [theme, setTheme] = useState<string | null>(null);
|
|
20
|
+
|
|
21
|
+
const isSidebar = applicationMode === 'sidebar';
|
|
22
|
+
const isSettings = applicationMode === 'settings';
|
|
23
|
+
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
initEventBus(pluginId);
|
|
26
|
+
|
|
27
|
+
// Check if we're in an iframe context - if not, we're standalone
|
|
28
|
+
const standaloneDetected = window === window.parent;
|
|
29
|
+
|
|
30
|
+
if (standaloneDetected && !standaloneClient) {
|
|
31
|
+
StandaloneClient.getInstance().then((client) => {
|
|
32
|
+
client.needsLogin().then((needLogin) => setStandaloneClient(needLogin ? client : true));
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ((!standaloneDetected && !plugin) || (standaloneDetected && standaloneClient === true)) {
|
|
37
|
+
RimoriClient.getInstance(pluginId).then((client) => {
|
|
38
|
+
setPlugin(client);
|
|
39
|
+
// Get applicationMode and theme from MessageChannel query params
|
|
40
|
+
if (!standaloneDetected) {
|
|
41
|
+
const mode = client.getQueryParam('applicationMode');
|
|
42
|
+
const themeParam = client.getQueryParam('rm_theme');
|
|
43
|
+
setApplicationMode(mode);
|
|
44
|
+
setTheme(themeParam);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}, [pluginId, standaloneClient]);
|
|
49
|
+
|
|
50
|
+
//route change
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (!plugin) return;
|
|
53
|
+
|
|
54
|
+
//sidebar pages should not report url changes
|
|
55
|
+
if (isSidebar) return;
|
|
56
|
+
|
|
57
|
+
let lastHash = window.location.hash;
|
|
58
|
+
const emitUrlChange = (url: string) => plugin.event.emit('session.triggerUrlChange', { url });
|
|
59
|
+
|
|
60
|
+
const interval = setInterval(() => {
|
|
61
|
+
if (lastHash === window.location.hash) return;
|
|
62
|
+
lastHash = window.location.hash;
|
|
63
|
+
// console.log('url changed:', lastHash);
|
|
64
|
+
emitUrlChange(lastHash);
|
|
65
|
+
}, 1000);
|
|
66
|
+
|
|
67
|
+
emitUrlChange(lastHash);
|
|
68
|
+
return () => clearInterval(interval);
|
|
69
|
+
}, [plugin]);
|
|
70
|
+
|
|
71
|
+
if (standaloneClient instanceof StandaloneClient) {
|
|
72
|
+
return (
|
|
73
|
+
<StandaloneAuth
|
|
74
|
+
onLogin={async (email, password) => {
|
|
75
|
+
if (await standaloneClient.login(email, password)) setStandaloneClient(true);
|
|
76
|
+
}}
|
|
77
|
+
/>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!plugin) {
|
|
82
|
+
return '';
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<PluginContext.Provider value={plugin}>
|
|
87
|
+
{!settings?.disableContextMenu && !isSidebar && !isSettings && <ContextMenu client={plugin} />}
|
|
88
|
+
{children}
|
|
89
|
+
</PluginContext.Provider>
|
|
90
|
+
);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export const useRimori = () => {
|
|
94
|
+
const context = useContext(PluginContext);
|
|
95
|
+
if (context === null) {
|
|
96
|
+
throw new Error('useRimori must be used within an PluginProvider');
|
|
97
|
+
}
|
|
98
|
+
return context;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
function getUrlParam(name: string) {
|
|
102
|
+
// First try to get from URL hash query params (for compatibility)
|
|
103
|
+
const hashParts = window.location.hash.split('?');
|
|
104
|
+
if (hashParts.length > 1) {
|
|
105
|
+
const hashParams = new URLSearchParams(hashParts[1]);
|
|
106
|
+
const hashValue = hashParams.get(name);
|
|
107
|
+
if (hashValue) return hashValue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Fallback to regular URL search params
|
|
111
|
+
const url = new URL(window.location.href);
|
|
112
|
+
return url.searchParams.get(name);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function initEventBus(pluginId: string) {
|
|
116
|
+
// For now, use URL fallback for EventBus naming - this will be updated once MessageChannel is ready
|
|
117
|
+
const isSidebar = getUrlParam('applicationMode') === 'sidebar';
|
|
118
|
+
EventBusHandler.getInstance('Plugin EventBus ' + pluginId + ' ' + (isSidebar ? 'sidebar' : 'main'));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function StandaloneAuth({ onLogin }: { onLogin: (user: string, password: string) => void }) {
|
|
122
|
+
const [user, setUser] = useState('');
|
|
123
|
+
const [password, setPassword] = useState('');
|
|
124
|
+
return (
|
|
125
|
+
<div
|
|
126
|
+
style={{
|
|
127
|
+
position: 'fixed',
|
|
128
|
+
inset: 0,
|
|
129
|
+
display: 'flex',
|
|
130
|
+
alignItems: 'center',
|
|
131
|
+
justifyContent: 'center',
|
|
132
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
<div
|
|
136
|
+
style={{
|
|
137
|
+
backgroundColor: '#343534',
|
|
138
|
+
padding: '1rem',
|
|
139
|
+
borderRadius: '0.5rem',
|
|
140
|
+
width: '500px',
|
|
141
|
+
flexDirection: 'column',
|
|
142
|
+
display: 'flex',
|
|
143
|
+
alignItems: 'center',
|
|
144
|
+
justifyContent: 'center',
|
|
145
|
+
}}
|
|
146
|
+
>
|
|
147
|
+
<p style={{ fontSize: '2rem', fontWeight: 'bold', marginBottom: '1rem', textAlign: 'center' }}>Rimori Login</p>
|
|
148
|
+
<p style={{ marginBottom: '1rem', textAlign: 'center' }}>
|
|
149
|
+
Please login with your Rimori developer account for this plugin to be able to access the Rimori platform the
|
|
150
|
+
same it will operate in the Rimori platform.
|
|
151
|
+
</p>
|
|
152
|
+
{/* email and password input */}
|
|
153
|
+
<input
|
|
154
|
+
style={{
|
|
155
|
+
marginBottom: '1rem',
|
|
156
|
+
width: '100%',
|
|
157
|
+
padding: '0.5rem',
|
|
158
|
+
borderRadius: '0.5rem',
|
|
159
|
+
border: 'none',
|
|
160
|
+
backgroundColor: '#444444',
|
|
161
|
+
}}
|
|
162
|
+
type="email"
|
|
163
|
+
placeholder="Email"
|
|
164
|
+
onChange={(e) => setUser(e.target.value)}
|
|
165
|
+
/>
|
|
166
|
+
<input
|
|
167
|
+
style={{
|
|
168
|
+
marginBottom: '1rem',
|
|
169
|
+
width: '100%',
|
|
170
|
+
padding: '0.5rem',
|
|
171
|
+
borderRadius: '0.5rem',
|
|
172
|
+
border: 'none',
|
|
173
|
+
backgroundColor: '#444444',
|
|
174
|
+
}}
|
|
175
|
+
type="password"
|
|
176
|
+
placeholder="Password"
|
|
177
|
+
onChange={(e) => setPassword(e.target.value)}
|
|
178
|
+
/>
|
|
179
|
+
<button
|
|
180
|
+
style={{
|
|
181
|
+
marginBottom: '1rem',
|
|
182
|
+
width: '100%',
|
|
183
|
+
padding: '0.5rem',
|
|
184
|
+
borderRadius: '0.5rem',
|
|
185
|
+
border: 'none',
|
|
186
|
+
backgroundColor: '#928358',
|
|
187
|
+
}}
|
|
188
|
+
onClick={() => {
|
|
189
|
+
onLogin(user, password);
|
|
190
|
+
}}
|
|
191
|
+
>
|
|
192
|
+
Login
|
|
193
|
+
</button>
|
|
194
|
+
</div>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
|
+
}
|
package/src/style.scss
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
dialog::backdrop {
|
|
2
|
+
backdrop-filter: blur(2px);
|
|
3
|
+
// background: rgb(255, 255, 255, 0.5);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.dark * dialog::backdrop {
|
|
7
|
+
background: transparent;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.tiptap {
|
|
11
|
+
padding-top: 5px;
|
|
12
|
+
padding-left: 7px;
|
|
13
|
+
/* min-height: 300px; */
|
|
14
|
+
|
|
15
|
+
&:focus-visible {
|
|
16
|
+
outline: none;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
h1,
|
|
20
|
+
h2,
|
|
21
|
+
h3,
|
|
22
|
+
h4,
|
|
23
|
+
h5,
|
|
24
|
+
h6 {
|
|
25
|
+
@apply font-bold;
|
|
26
|
+
margin-bottom: 1rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
h1 {
|
|
30
|
+
@apply text-4xl;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
h2 {
|
|
34
|
+
@apply text-3xl;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
h3 {
|
|
38
|
+
@apply text-2xl;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
h4 {
|
|
42
|
+
@apply text-xl;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
h5 {
|
|
46
|
+
@apply text-lg;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
h6 {
|
|
50
|
+
@apply text-base;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
p {
|
|
54
|
+
@apply mb-4;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
a {
|
|
58
|
+
@apply text-blue-600 hover:text-blue-800;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
a:hover {
|
|
63
|
+
@apply underline;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ul {
|
|
67
|
+
@apply list-disc pl-8;
|
|
68
|
+
|
|
69
|
+
li > p {
|
|
70
|
+
@apply mb-1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
ol {
|
|
75
|
+
@apply list-decimal pl-7;
|
|
76
|
+
|
|
77
|
+
li > p {
|
|
78
|
+
@apply mb-1;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
blockquote {
|
|
83
|
+
@apply border-l-4 pl-4 italic text-gray-600 my-4;
|
|
84
|
+
border-color: #ccc;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
code {
|
|
88
|
+
font-family: monospace;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pre {
|
|
92
|
+
@apply bg-gray-800 text-gray-500 p-4 rounded-lg overflow-x-auto;
|
|
93
|
+
font-family: monospace;
|
|
94
|
+
white-space: pre-wrap;
|
|
95
|
+
word-wrap: break-word;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
img {
|
|
99
|
+
@apply max-w-full h-auto rounded-lg my-4;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
table {
|
|
103
|
+
@apply table-auto w-full border-collapse mb-4;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
th,
|
|
107
|
+
td {
|
|
108
|
+
@apply border px-4 py-2 text-left;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
th {
|
|
112
|
+
@apply bg-gray-500 font-semibold;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
tr:nth-child(even) {
|
|
116
|
+
@apply bg-gray-400;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@media (max-width: 768px) {
|
|
120
|
+
h1 {
|
|
121
|
+
@apply text-3xl;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
h2 {
|
|
125
|
+
@apply text-2xl;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
p {
|
|
129
|
+
@apply text-base;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
img {
|
|
133
|
+
@apply max-w-full;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function isFullscreen() {
|
|
2
|
+
return !!document.fullscreenElement;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function triggerFullscreen(onStateChange: (isFullscreen: boolean) => void, selector?: string) {
|
|
6
|
+
document.addEventListener('fullscreenchange', () => {
|
|
7
|
+
onStateChange(isFullscreen());
|
|
8
|
+
});
|
|
9
|
+
try {
|
|
10
|
+
const ref = document.querySelector(selector || '#root')!;
|
|
11
|
+
if (!isFullscreen()) {
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
ref.requestFullscreen() || ref.webkitRequestFullscreen();
|
|
14
|
+
} else {
|
|
15
|
+
// @ts-ignore
|
|
16
|
+
document.exitFullscreen() || document.webkitExitFullscreen();
|
|
17
|
+
}
|
|
18
|
+
} catch (error: any) {
|
|
19
|
+
console.error('Failed to enter fullscreen', error.message);
|
|
20
|
+
}
|
|
21
|
+
onStateChange(isFullscreen());
|
|
22
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "dist",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"target": "ES6",
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"moduleResolution": "node",
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"strict": true,
|
|
12
|
+
"baseUrl": ".",
|
|
13
|
+
"paths": {
|
|
14
|
+
"@rimori/client": [
|
|
15
|
+
"../rimori-client/src/index.ts"
|
|
16
|
+
],
|
|
17
|
+
"@rimori/client/*": [
|
|
18
|
+
"../rimori-client/src/*"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"include": ["src/**/*"]
|
|
23
|
+
}
|