js-dos 7.4.9 → 8.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 (155) hide show
  1. package/.github/workflows/build.yml +51 -0
  2. package/.gitmodules +4 -0
  3. package/README.deployment.md +11 -0
  4. package/README.md +29 -89
  5. package/index.html +106 -0
  6. package/package.json +46 -71
  7. package/postcss.config.cjs +8 -0
  8. package/src/app.css +14 -0
  9. package/src/base.css +10 -0
  10. package/src/components/checkbox.tsx +41 -0
  11. package/src/components/close-button.tsx +17 -0
  12. package/src/components/components.css +28 -0
  13. package/src/components/dos-option-checkbox.tsx +94 -0
  14. package/src/components/dos-option-select.tsx +108 -0
  15. package/src/components/dos-option-slider.tsx +35 -0
  16. package/src/components/error.tsx +16 -0
  17. package/src/components/loading.tsx +26 -0
  18. package/src/components/lock.tsx +10 -0
  19. package/src/components/select.tsx +33 -0
  20. package/src/components/slider.tsx +69 -0
  21. package/src/download-file.ts +18 -0
  22. package/src/frame/account-frame.tsx +156 -0
  23. package/src/frame/editor/defaults.ts +419 -0
  24. package/src/frame/editor/editor-conf-frame.tsx +226 -0
  25. package/src/frame/editor/editor-frame.css +55 -0
  26. package/src/frame/editor/editor-fs-frame.tsx +314 -0
  27. package/src/frame/fat-drives-frame.tsx +135 -0
  28. package/src/frame/frame.css +119 -0
  29. package/src/frame/frame.tsx +34 -0
  30. package/src/frame/image-rendering-frame.tsx +8 -0
  31. package/src/frame/network-frame.tsx +157 -0
  32. package/src/frame/quick-save-frame.tsx +96 -0
  33. package/src/frame/settings-frame.tsx +14 -0
  34. package/src/frame/stats-frame.tsx +87 -0
  35. package/src/host/bundle-storage.ts +91 -0
  36. package/src/host/fullscreen.ts +35 -0
  37. package/src/host/lcache.ts +203 -0
  38. package/src/host/lstorage.ts +156 -0
  39. package/src/i18n.ts +179 -0
  40. package/src/index.css +7 -0
  41. package/src/load.ts +132 -0
  42. package/src/login/login.css +9 -0
  43. package/src/login/login.tsx +77 -0
  44. package/src/main.tsx +197 -0
  45. package/src/public/types.ts +41 -0
  46. package/src/sidebar/account-button.tsx +33 -0
  47. package/src/sidebar/cloud-save-button.tsx +89 -0
  48. package/src/sidebar/diskette-icon.tsx +14 -0
  49. package/src/sidebar/fullscreen-button.tsx +44 -0
  50. package/src/sidebar/network-button.tsx +39 -0
  51. package/src/sidebar/sidebar-button.tsx +244 -0
  52. package/src/sidebar/sidebar.css +47 -0
  53. package/src/sidebar/sidebar.tsx +30 -0
  54. package/src/sockdrive/LICENSE +674 -0
  55. package/src/sockdrive/README.md +45 -0
  56. package/src/sockdrive/include/sockdrive.h +23 -0
  57. package/src/sockdrive/js/.eslintrc.json +43 -0
  58. package/src/sockdrive/js/package.json +29 -0
  59. package/src/sockdrive/js/src/fatfs/chains.js +318 -0
  60. package/src/sockdrive/js/src/fatfs/dir.js +385 -0
  61. package/src/sockdrive/js/src/fatfs/helpers.js +210 -0
  62. package/src/sockdrive/js/src/fatfs/index.js +606 -0
  63. package/src/sockdrive/js/src/fatfs/structs.js +255 -0
  64. package/src/sockdrive/js/src/fatfs/vol.js +166 -0
  65. package/src/sockdrive/js/src/sockdrive/cache.ts +133 -0
  66. package/src/sockdrive/js/src/sockdrive/drive.ts +457 -0
  67. package/src/sockdrive/js/src/sockdrive/lru.ts +221 -0
  68. package/src/sockdrive/js/src/sockdrive/types.ts +14 -0
  69. package/src/sockdrive/js/src/sockdrive-fat.d.ts +64 -0
  70. package/src/sockdrive/js/src/sockdrive-fat.ts +226 -0
  71. package/src/sockdrive/js/src/sockdrive-native.ts +100 -0
  72. package/src/sockdrive/js/src/test/test.ts +288 -0
  73. package/src/sockdrive/js/tsconfig.json +11 -0
  74. package/src/sockdrive/js/webpack.config.js +68 -0
  75. package/src/sockdrive/js/yarn.lock +1808 -0
  76. package/src/store/auth.ts +115 -0
  77. package/src/store/dos.ts +305 -0
  78. package/src/store/editor.ts +61 -0
  79. package/src/store/init.ts +48 -0
  80. package/src/store/storage.ts +32 -0
  81. package/src/store/ui.ts +186 -0
  82. package/src/store.tsx +108 -0
  83. package/src/ui.tsx +104 -0
  84. package/src/v8/changes.ts +56 -0
  85. package/src/v8/config.ts +18 -0
  86. package/src/v8/subscriptions.ts +62 -0
  87. package/src/vite-env.d.ts +2 -0
  88. package/src/window/dos/controls/keyboard.ts +32 -0
  89. package/src/window/dos/controls/keys.ts +331 -0
  90. package/src/window/dos/controls/mouse/mount.ts +99 -0
  91. package/src/window/dos/controls/mouse/mouse-locked.ts +51 -0
  92. package/src/window/dos/controls/mouse/mouse-not-locked.ts +84 -0
  93. package/src/window/dos/controls/mouse/mouse-swipe.ts +57 -0
  94. package/src/window/dos/controls/mouse/pointer.ts +85 -0
  95. package/src/window/dos/controls/mouse.ts +21 -0
  96. package/src/window/dos/dos-dhry2.tsx +191 -0
  97. package/src/window/dos/dos-runtime.tsx +214 -0
  98. package/src/window/dos/dos-window.tsx +84 -0
  99. package/src/window/dos/render/canvas.ts +65 -0
  100. package/src/window/dos/render/resize.ts +31 -0
  101. package/src/window/dos/render/webgl.ts +173 -0
  102. package/src/window/dos/sound/audio-node.ts +148 -0
  103. package/src/window/error-window.tsx +9 -0
  104. package/src/window/loading-window.tsx +54 -0
  105. package/src/window/prerun-window.tsx +123 -0
  106. package/src/window/select-window.tsx +118 -0
  107. package/src/window/window.css +78 -0
  108. package/src/window/window.tsx +49 -0
  109. package/src/ws/ws-sockdrive.ts +101 -0
  110. package/src/ws/ws-transport-layer.ts +455 -0
  111. package/tailwind.config.cjs +48 -0
  112. package/tsconfig.json +32 -0
  113. package/tsconfig.node.json +9 -0
  114. package/vite.config.ts +22 -0
  115. package/LICENSE +0 -339
  116. package/dist/emulators-ui-loader.png +0 -0
  117. package/dist/js-dos.css +0 -1690
  118. package/dist/js-dos.js +0 -17
  119. package/dist/js-dos.js.map +0 -1
  120. package/dist/types/src/backend/v7/latency.d.ts +0 -8
  121. package/dist/types/src/backend/v7/personal.d.ts +0 -2
  122. package/dist/types/src/backend/v7/v7-config.d.ts +0 -16
  123. package/dist/types/src/components/action-bar.d.ts +0 -2
  124. package/dist/types/src/components/action-hide.d.ts +0 -4
  125. package/dist/types/src/components/action-save-or-exit.d.ts +0 -4
  126. package/dist/types/src/components/client.d.ts +0 -6
  127. package/dist/types/src/components/controls.d.ts +0 -8
  128. package/dist/types/src/components/cpu-control.d.ts +0 -2
  129. package/dist/types/src/components/horizontal-slider.d.ts +0 -13
  130. package/dist/types/src/components/region.d.ts +0 -6
  131. package/dist/types/src/components/scale-control.d.ts +0 -3
  132. package/dist/types/src/components/sensitivity-control.d.ts +0 -3
  133. package/dist/types/src/components/sidebar/latency-info.d.ts +0 -7
  134. package/dist/types/src/components/sidebar/main.d.ts +0 -2
  135. package/dist/types/src/components/sidebar/networking.d.ts +0 -2
  136. package/dist/types/src/components/sidebar/token/token-add-time.d.ts +0 -2
  137. package/dist/types/src/components/sidebar/token/token-select.d.ts +0 -2
  138. package/dist/types/src/components/sidebar/token/token.d.ts +0 -17
  139. package/dist/types/src/components/sidebar.d.ts +0 -2
  140. package/dist/types/src/components/sync-control.d.ts +0 -2
  141. package/dist/types/src/components/tip.d.ts +0 -2
  142. package/dist/types/src/components/vertical-slider.d.ts +0 -12
  143. package/dist/types/src/components/volume-control.d.ts +0 -3
  144. package/dist/types/src/dom.d.ts +0 -8
  145. package/dist/types/src/hardware-transport-layer.d.ts +0 -18
  146. package/dist/types/src/icons.d.ts +0 -95
  147. package/dist/types/src/player-app.d.ts +0 -50
  148. package/dist/types/src/player.d.ts +0 -29
  149. package/dist/types/src/request.d.ts +0 -1
  150. package/dist/types/src/xhr.d.ts +0 -6
  151. package/dist/types/v7-services/src/personal.d.ts +0 -3
  152. package/dist/wdosbox.js +0 -55
  153. package/dist/wdosbox.js.symbols +0 -3174
  154. package/dist/wdosbox.wasm +0 -0
  155. package/examples/digger/index.html +0 -71
package/src/main.tsx ADDED
@@ -0,0 +1,197 @@
1
+ import { render } from "preact";
2
+ import "./index.css";
3
+
4
+ import { Provider } from "react-redux";
5
+ import { Ui } from "./ui";
6
+ import { dosSlice } from "./store/dos";
7
+ import { initEmulators } from "./store/dos";
8
+ // eslint-disable-next-line
9
+ import { uiSlice } from "./store/ui";
10
+ import { i18nSlice } from "./i18n";
11
+ import { getCache } from "./host/lcache";
12
+ import { loadBundleFromConfg, loadBundleFromUrl } from "./load";
13
+
14
+ import { DosOptions, DosProps, DosFn } from "./public/types";
15
+ import { browserSetFullScreen } from "./host/fullscreen";
16
+ import { NonSerializableStore, Store, makeNonSerializableStore, makeStore, postJsDosEvent } from "./store";
17
+
18
+ export const Dos: DosFn = (element: HTMLDivElement,
19
+ options: Partial<DosOptions> = {}): DosProps => {
20
+ const nonSerializableStore = makeNonSerializableStore(options);
21
+ const store = makeStore(nonSerializableStore);
22
+
23
+
24
+ if (store.getState().auth.account?.email === "dz.caiiiycuk@gmail.com" ||
25
+ store.getState().auth.account?.email === "caiiiycuk@gmail.com") {
26
+ store.dispatch(dosSlice.actions.setSockdriveWrite(false));
27
+ }
28
+
29
+ setupRootElement(element, nonSerializableStore, store);
30
+
31
+ let pollStep = "none";
32
+ function pollEvents() {
33
+ (async () => {
34
+ const state = store.getState();
35
+ const step = state.dos.step;
36
+
37
+ if (step === pollStep) {
38
+ return;
39
+ }
40
+ pollStep = step;
41
+
42
+ switch (state.dos.step) {
43
+ case "emu-ready": {
44
+ const cachedEmail = state.auth.account?.email;
45
+ nonSerializableStore.cache = await getCache(cachedEmail ?? "guest");
46
+
47
+ if (nonSerializableStore.options.url) {
48
+ try {
49
+ await loadBundleFromUrl(nonSerializableStore.options.url, store);
50
+ } catch (e: any) {
51
+ store.dispatch(dosSlice.actions.bndError(e.message));
52
+ }
53
+ } else if (nonSerializableStore.options.dosboxConf) {
54
+ loadBundleFromConfg({
55
+ dosboxConf: nonSerializableStore.options.dosboxConf,
56
+ jsdosConf: {
57
+ version: "8",
58
+ },
59
+ }, store);
60
+ } else {
61
+ store.dispatch(uiSlice.actions.windowSelect());
62
+ }
63
+
64
+ postJsDosEvent(nonSerializableStore, "emu-ready");
65
+ } break;
66
+ };
67
+ })().catch(console.error);
68
+ }
69
+ store.subscribe(pollEvents);
70
+
71
+ initEmulators(store, options.pathPrefix ?? "https://v8.js-dos.com/latest/emulators/");
72
+
73
+ function setTheme(theme: DosOptions["theme"]) {
74
+ store.dispatch(uiSlice.actions.theme(theme));
75
+ }
76
+
77
+ function setLang(lang: DosOptions["lang"]) {
78
+ store.dispatch(i18nSlice.actions.setLang(lang));
79
+ }
80
+
81
+ function setBackend(backend: DosOptions["backend"]) {
82
+ store.dispatch(dosSlice.actions.dosBackend(backend));
83
+ }
84
+
85
+ function setBackendLocked(locked: boolean) {
86
+ store.dispatch(dosSlice.actions.dosBackendLocked(locked));
87
+ }
88
+
89
+ function setWorkerThread(workerThread: DosOptions["workerThread"]) {
90
+ store.dispatch(dosSlice.actions.dosWorker(workerThread));
91
+ }
92
+
93
+ function setMouseCapture(capture: DosOptions["mouseCapture"]) {
94
+ store.dispatch(dosSlice.actions.mouseCapture(capture));
95
+ }
96
+
97
+ function setServer(server: DosOptions["server"]) {
98
+ store.dispatch(dosSlice.actions.setServer(server));
99
+ }
100
+
101
+ function setRoom(room: DosOptions["room"]) {
102
+ store.dispatch(dosSlice.actions.setRoom(room));
103
+ }
104
+
105
+ function setFrame(frame: "network") {
106
+ store.dispatch(uiSlice.actions.frameNetwork());
107
+ }
108
+
109
+ function setBackground(background: string) {
110
+ store.dispatch(uiSlice.actions.background(background));
111
+ }
112
+
113
+ function setFullScreen(fullScreen: boolean) {
114
+ browserSetFullScreen(fullScreen, store);
115
+ }
116
+
117
+ if (options.theme) {
118
+ setTheme(options.theme);
119
+ }
120
+
121
+ if (options.lang) {
122
+ setLang(options.lang);
123
+ }
124
+
125
+ if (options.backend) {
126
+ setBackend(options.backend);
127
+ }
128
+
129
+ if (options.backendLocked) {
130
+ setBackendLocked(options.backendLocked);
131
+ }
132
+
133
+ if (options.workerThread !== undefined) {
134
+ setWorkerThread(options.workerThread);
135
+ }
136
+
137
+ if (options.mouseCapture !== undefined) {
138
+ setMouseCapture(options.mouseCapture);
139
+ }
140
+
141
+ if (options.server) {
142
+ setServer(options.server);
143
+ }
144
+
145
+ if (options.room) {
146
+ setRoom(options.room);
147
+ }
148
+
149
+ if (options.background) {
150
+ setBackground(options.background);
151
+ }
152
+
153
+ if (options.fullScreen !== undefined) {
154
+ setFullScreen(options.fullScreen);
155
+ }
156
+
157
+ render(
158
+ <Provider store={store}>
159
+ {<Ui /> as any}
160
+ </Provider>,
161
+ element,
162
+ );
163
+
164
+ return {
165
+ setTheme,
166
+ setLang,
167
+ setBackend,
168
+ setBackendLocked,
169
+ setWorkerThread,
170
+ setMouseCapture,
171
+ setServer,
172
+ setRoom,
173
+ setFrame,
174
+ setBackground,
175
+ setFullScreen,
176
+ };
177
+ };
178
+
179
+ function setupRootElement(root: HTMLDivElement, nonSerializableStore: NonSerializableStore, store: Store) {
180
+ nonSerializableStore.root = root;
181
+ root.classList.add("jsdos-rso");
182
+ root.addEventListener("contextmenu", (e) => {
183
+ if (e.target !== null &&
184
+ (e.target as HTMLElement).classList?.contains("contextmenu")) {
185
+ return;
186
+ }
187
+ e.stopPropagation();
188
+ e.preventDefault();
189
+ return false;
190
+ });
191
+ document.addEventListener("fullscreenchange", () => {
192
+ const fullscreen = document.fullscreenElement === root;
193
+ store.dispatch(uiSlice.actions.setFullScreen(fullscreen));
194
+ });
195
+ }
196
+
197
+ (window as any).Dos = Dos;
@@ -0,0 +1,41 @@
1
+ export type DosEvent = "emu-ready" | "ci-ready" | "bnd-play";
2
+
3
+ export interface DosOptions {
4
+ url: string,
5
+ dosboxConf: string,
6
+ background: string,
7
+ pathPrefix: string,
8
+ theme: "light" | "dark" | "cupcake" | "bumblebee" | "emerald" | "corporate" |
9
+ "synthwave" | "retro" | "cyberpunk" | "valentine" | "halloween" | "garden" |
10
+ "forest" | "aqua" | "lofi" | "pastel" | "fantasy" | "wireframe" | "black" |
11
+ "luxury" | "dracula" | "cmyk" | "autumn" | "business" | "acid" | "lemonade" |
12
+ "night" | "coffee" | "winter",
13
+ lang: "ru" | "en",
14
+ backend: "dosbox" | "dosboxX",
15
+ backendLocked: boolean,
16
+ backendHardware: ((backend: "dosbox" | "dosboxX") => Promise<string | null>),
17
+ workerThread: boolean,
18
+ mouseCapture: boolean,
19
+ onEvent: (event: DosEvent, ci?: any /* CommandInterface */) => void,
20
+ server: "netherlands" | "newyork" | "singapore",
21
+ room: string,
22
+ fullScreen: boolean,
23
+ }
24
+
25
+ export interface DosProps {
26
+ setTheme(theme: DosOptions["theme"]): void;
27
+ setLang(lang: DosOptions["lang"]): void;
28
+ setBackend(backend: DosOptions["backend"]): void;
29
+ setBackendLocked(locked: boolean): void;
30
+ setWorkerThread(capture: DosOptions["workerThread"]): void;
31
+ setMouseCapture(capture: DosOptions["mouseCapture"]): void;
32
+ setServer(server: DosOptions["server"]): void;
33
+ setRoom(room: DosOptions["room"]): void;
34
+ setFrame(frame: "network"): void;
35
+ setBackground(background: string | null): void;
36
+ setFullScreen(fullScreen: boolean): void;
37
+ }
38
+
39
+ export type DosFn = (element: HTMLDivElement, options: Partial<DosOptions>) => DosProps;
40
+
41
+ // declare const Dos: DosFn;
@@ -0,0 +1,33 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { dispatchLoginAction } from "../store/ui";
3
+ import { State } from "../store";
4
+
5
+ export function AccountButton(props: {
6
+ class?: string,
7
+ }) {
8
+ const account = useSelector((state: State) => state.auth.account);
9
+ const loggedIn = account !== null;
10
+ const hightlight = useSelector((state: State) => state.ui.frame) === "account";
11
+ const dispatch = useDispatch();
12
+
13
+ function onClick() {
14
+ dispatchLoginAction(account, dispatch);
15
+ }
16
+
17
+ return <div class={"sidebar-button " + (hightlight ? "sidebar-highlight " : "") +
18
+ (account?.email === "dz.caiiiycuk@gmail.com" ? "bg-accent " : "") +
19
+ props.class} onClick={onClick}>
20
+
21
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none"
22
+ viewBox="0 0 24 24" stroke-width="1.5"
23
+ stroke="currentColor" class="w-full h-full">
24
+ <path stroke-linecap="round"
25
+ stroke-linejoin="round"
26
+ d="M17.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963
27
+ 0m11.963 0A8.966 8.966 0 0112 21a8.966
28
+ 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" />
29
+ </svg>
30
+
31
+ {loggedIn === false && <div class="sidebar-badge" />}
32
+ </div>;
33
+ }
@@ -0,0 +1,89 @@
1
+ import { useState } from "preact/hooks";
2
+ import { useDispatch, useSelector } from "react-redux";
3
+ import { LockBadge } from "../components/lock";
4
+ import { State, useNonSerializableStore } from "../store";
5
+ import { uiSlice } from "../store/ui";
6
+ import { DisketteIcon } from "./diskette-icon";
7
+ import { useT } from "../i18n";
8
+ import { putChanges } from "../v8/changes";
9
+
10
+ export function CloudSaveButton(props: {
11
+ class?: string,
12
+ }) {
13
+ const [busy, setBusy] = useState<boolean>(false);
14
+ const account = useSelector((state: State) => state.auth.account);
15
+ const disabled = account === null;
16
+ const dispatch = useDispatch();
17
+ const t = useT();
18
+ const cloudSaves = useSelector((state: State) => state.ui.cloudSaves);
19
+ const nonSerializableStore = useNonSerializableStore();
20
+
21
+ if (!cloudSaves ||
22
+ nonSerializableStore.loadedBundle === null ||
23
+ nonSerializableStore.loadedBundle.bundleChangesUrl === null) {
24
+ return null;
25
+ }
26
+
27
+ async function onClick() {
28
+ if (disabled) {
29
+ dispatch(uiSlice.actions.modalLogin());
30
+ return;
31
+ }
32
+
33
+ if (busy) {
34
+ return;
35
+ }
36
+
37
+ const ci = nonSerializableStore.ci;
38
+ const changesUrl = nonSerializableStore.loadedBundle?.bundleChangesUrl;
39
+
40
+ if (ci === null || !changesUrl) {
41
+ return;
42
+ }
43
+
44
+ setBusy(true);
45
+ try {
46
+ const changes = await ci.persist(true);
47
+ if (changes !== null) {
48
+ if (account === null || !account.premium) {
49
+ await nonSerializableStore.cache.put(changesUrl, changes);
50
+ } else {
51
+ await Promise.all([
52
+ putChanges(changesUrl, changes),
53
+ nonSerializableStore.cache.put(changesUrl, changes),
54
+ ]);
55
+ }
56
+ }
57
+
58
+ dispatch(uiSlice.actions.showToast({
59
+ message: t("success"),
60
+ intent: "success",
61
+ }));
62
+ } catch (e: any) {
63
+ dispatch(uiSlice.actions.showToast({
64
+ message: t("unable_to_save"),
65
+ intent: "error",
66
+ }));
67
+ console.error(e);
68
+ } finally {
69
+ setBusy(false);
70
+ }
71
+ }
72
+
73
+ return <div class={"save-button sidebar-button overflow-hidden " +
74
+ (busy ? " sidebar-highlight " : "") + props.class +
75
+ (disabled ? " opacity-50" : "")} onClick={onClick}>
76
+ <div class="w-full h-full flex justify-center">
77
+ <DisketteIcon />
78
+ {busy && <div class="sidebar-badge" />}
79
+ {disabled && <LockBadge />}
80
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
81
+ stroke-width="1.5" stroke="currentColor"
82
+ class="absolute bottom-1 w-3 h-3 text-primary-content">
83
+ <path stroke-linecap="round" stroke-linejoin="round"
84
+ d="M12 16.5V9.75m0 0l3 3m-3-3l-3 3M6.75 19.5a4.5 4.5 0 01-1.41-8.775
85
+ 5.25 5.25 0 0110.233-2.33 3 3 0 013.758 3.848A3.752 3.752 0 0118 19.5H6.75z" />
86
+ </svg>
87
+ </div>
88
+ </div >;
89
+ }
@@ -0,0 +1,14 @@
1
+ export function DisketteIcon(props: {
2
+ class?: string,
3
+ }) {
4
+ return <svg xmlns="http://www.w3.org/2000/svg"
5
+ style="padding: 2px"
6
+ viewBox="0 0 16 16" enable-background="new 0 0 16 16"
7
+ fill="currentColor" class={ "w-full h-full rounded-lg " + props.class }>
8
+ <path fill-rule="evenodd" clip-rule="evenodd"
9
+ d="M15.71,2.29l-2-2C13.53,0.11,13.28,0,13,0h-1v6H4V0H1C0.45,0,0,0.45,0,1v14
10
+ c0,0.55,0.45,1,1,1h14c0.55,0,1-0.45,1-1V3C16,2.72,15.89,2.47,15.71,2.29z
11
+ M14,15H2V9c0-0.55,0.45-1,1-1h10c0.55,0,1,0.45,1,1V15
12
+ z M11,1H9v4h2V1z"/>
13
+ </svg>;
14
+ }
@@ -0,0 +1,44 @@
1
+ import { useSelector, useStore } from "react-redux";
2
+ import { State, Store } from "../store";
3
+ import { browserSetFullScreen } from "../host/fullscreen";
4
+
5
+ export function FullscreenButton(props: {
6
+ class?: string,
7
+ }) {
8
+ const fullScreen = useSelector((state: State) => state.ui.fullScreen);
9
+ const store = useStore() as Store;
10
+
11
+ function onClick() {
12
+ browserSetFullScreen(!fullScreen, store);
13
+ }
14
+ /* eslint-disable max-len */
15
+ return <div class={"fullscreen-button sidebar-button " + props.class} onClick={onClick}>
16
+ <div class={"w-full h-full scale-75 hover:scale-90"}>
17
+ {!fullScreen &&
18
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
19
+ viewBox="0 0 16 16" fill="currentColor" stroke="none" enable-background="new 0 0 16 16" >
20
+ <g>
21
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M5.99,8.99c-0.28,0-0.53,0.11-0.71,0.29l-3.29,3.29v-1.59c0-0.55-0.45-1-1-1
22
+ s-1,0.45-1,1v4c0,0.55,0.45,1,1,1h4c0.55,0,1-0.45,1-1s-0.45-1-1-1H3.41L6.7,10.7c0.18-0.18,0.29-0.43,0.29-0.71
23
+ C6.99,9.44,6.54,8.99,5.99,8.99z M14.99-0.01h-4c-0.55,0-1,0.45-1,1s0.45,1,1,1h1.59L9.28,5.29C9.1,5.47,8.99,5.72,8.99,5.99
24
+ c0,0.55,0.45,1,1,1c0.28,0,0.53-0.11,0.71-0.29l3.29-3.29v1.59c0,0.55,0.45,1,1,1s1-0.45,1-1v-4C15.99,0.44,15.54-0.01,14.99-0.01
25
+ z"/>
26
+ </g>
27
+ </svg>
28
+ }
29
+ {fullScreen &&
30
+ <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
31
+ viewBox="0 0 16 16" fill="currentColor" stroke="none" enable-background="new 0 0 16 16">
32
+ <g>
33
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M15.99,0.99c0-0.55-0.45-1-1-1c-0.28,0-0.53,0.11-0.71,0.29l-3.29,3.29V1.99
34
+ c0-0.55-0.45-1-1-1s-1,0.45-1,1v4c0,0.55,0.45,1,1,1h4c0.55,0,1-0.45,1-1s-0.45-1-1-1h-1.59L15.7,1.7
35
+ C15.88,1.52,15.99,1.27,15.99,0.99z M5.99,8.99h-4c-0.55,0-1,0.45-1,1s0.45,1,1,1h1.59l-3.29,3.29c-0.18,0.18-0.29,0.43-0.29,0.71
36
+ c0,0.55,0.45,1,1,1c0.28,0,0.53-0.11,0.71-0.29l3.29-3.29v1.59c0,0.55,0.45,1,1,1s1-0.45,1-1v-4C6.99,9.44,6.54,8.99,5.99,8.99z"
37
+ />
38
+ </g>
39
+ </svg>
40
+ }
41
+ </div>
42
+ </div >;
43
+ /* eslint-enable max-len */
44
+ }
@@ -0,0 +1,39 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { State } from "../store";
3
+ import { uiSlice } from "../store/ui";
4
+
5
+ export function NetworkButton(props: {
6
+ class?: string,
7
+ }) {
8
+ const hightlight = useSelector((state: State) => state.ui.frame) === "network";
9
+ const inactive = useSelector((state: State) => state.dos.network.ipx !== "connected");
10
+ const dispatch = useDispatch();
11
+
12
+ function onClick() {
13
+ if (hightlight) {
14
+ dispatch(uiSlice.actions.frameNone());
15
+ } else {
16
+ dispatch(uiSlice.actions.frameNetwork());
17
+ }
18
+ }
19
+
20
+ return <div class={"network-button sidebar-button " +
21
+ (hightlight ? " sidebar-highlight " : "") +
22
+ (inactive ? " inactive " : "") +
23
+ props.class} onClick={onClick}>
24
+ <div class="w-full h-full">
25
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
26
+ stroke-width="1.5" stroke="currentColor" class="w-full h-full">
27
+ <path stroke-linecap="round" stroke-linejoin="round" d="M8.288 15.038a5.25 5.25 0
28
+ 017.424 0M5.106 11.856c3.807-3.808 9.98-3.808 13.788 0M1.924 8.674c5.565-5.565
29
+ 14.587-5.565 20.152 0M12.53 18.22l-.53.53-.53-.53a.75.75 0 011.06 0z" />
30
+ </svg>
31
+ { inactive && <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
32
+ stroke="currentColor" class="w-full text-error h-full absolute top-0 left-0">
33
+ <path stroke-linecap="round" stroke-linejoin="round" d="M4 4L18 18" />
34
+ </svg> }
35
+ </div>
36
+
37
+
38
+ </div >;
39
+ }