js-dos 8.1.5 → 8.1.7

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 (140) hide show
  1. package/dist/emulators/emulators.js +2 -0
  2. package/dist/emulators/emulators.js.map +1 -0
  3. package/dist/emulators/types/build.d.ts +28 -0
  4. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  5. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  6. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  7. package/dist/emulators/types/emulators.d.ts +76 -0
  8. package/dist/emulators/types/http.d.ts +9 -0
  9. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  10. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  11. package/dist/emulators/types/impl/modules.d.ts +38 -0
  12. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  13. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  14. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  15. package/dist/emulators/wdosbox-x.js +55 -0
  16. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  17. package/dist/emulators/wdosbox-x.wasm +0 -0
  18. package/dist/emulators/wdosbox.js +55 -0
  19. package/dist/emulators/wdosbox.js.symbols +3001 -0
  20. package/dist/emulators/wdosbox.wasm +0 -0
  21. package/dist/emulators/wlibzip.js +21 -0
  22. package/dist/emulators/wlibzip.js.symbols +268 -0
  23. package/dist/emulators/wlibzip.wasm +0 -0
  24. package/dist/js-dos.css +1 -0
  25. package/dist/js-dos.js +22 -0
  26. package/dist/js-dos.js.map +1 -0
  27. package/package.json +1 -1
  28. package/release.zip +0 -0
  29. package/.eslintrc.json +0 -43
  30. package/.github/workflows/build.yml +0 -51
  31. package/.gitmodules +0 -4
  32. package/index.html +0 -110
  33. package/postcss.config.cjs +0 -8
  34. package/src/app.css +0 -14
  35. package/src/base.css +0 -10
  36. package/src/components/checkbox.tsx +0 -41
  37. package/src/components/close-button.tsx +0 -17
  38. package/src/components/components.css +0 -28
  39. package/src/components/dos-option-checkbox.tsx +0 -94
  40. package/src/components/dos-option-select.tsx +0 -108
  41. package/src/components/dos-option-slider.tsx +0 -35
  42. package/src/components/error.tsx +0 -16
  43. package/src/components/loading.tsx +0 -26
  44. package/src/components/lock.tsx +0 -10
  45. package/src/components/select.tsx +0 -33
  46. package/src/components/slider.tsx +0 -69
  47. package/src/download-file.ts +0 -18
  48. package/src/frame/account-frame.tsx +0 -156
  49. package/src/frame/editor/defaults.ts +0 -419
  50. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  51. package/src/frame/editor/editor-frame.css +0 -55
  52. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  53. package/src/frame/fat-drives-frame.tsx +0 -199
  54. package/src/frame/frame.css +0 -119
  55. package/src/frame/frame.tsx +0 -34
  56. package/src/frame/image-rendering-frame.tsx +0 -8
  57. package/src/frame/network-frame.tsx +0 -157
  58. package/src/frame/quick-save-frame.tsx +0 -98
  59. package/src/frame/settings-frame.tsx +0 -14
  60. package/src/frame/stats-frame.tsx +0 -87
  61. package/src/host/bundle-storage.ts +0 -91
  62. package/src/host/fullscreen.ts +0 -35
  63. package/src/host/lcache.ts +0 -203
  64. package/src/host/lstorage.ts +0 -156
  65. package/src/i18n.ts +0 -185
  66. package/src/index.css +0 -7
  67. package/src/load.ts +0 -132
  68. package/src/login/login.css +0 -9
  69. package/src/login/login.tsx +0 -77
  70. package/src/main.tsx +0 -197
  71. package/src/public/types.ts +0 -45
  72. package/src/sidebar/account-button.tsx +0 -33
  73. package/src/sidebar/cloud-save-button.tsx +0 -89
  74. package/src/sidebar/diskette-icon.tsx +0 -14
  75. package/src/sidebar/fullscreen-button.tsx +0 -44
  76. package/src/sidebar/network-button.tsx +0 -39
  77. package/src/sidebar/sidebar-button.tsx +0 -244
  78. package/src/sidebar/sidebar.css +0 -47
  79. package/src/sidebar/sidebar.tsx +0 -30
  80. package/src/sockdrive/LICENSE +0 -674
  81. package/src/sockdrive/README.md +0 -45
  82. package/src/sockdrive/include/sockdrive.h +0 -23
  83. package/src/sockdrive/js/.eslintrc.json +0 -43
  84. package/src/sockdrive/js/package.json +0 -29
  85. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  86. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  87. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  88. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  89. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  90. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  91. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  92. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  93. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  94. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  95. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  96. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  97. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  98. package/src/sockdrive/js/src/test/test.ts +0 -289
  99. package/src/sockdrive/js/tsconfig.json +0 -11
  100. package/src/sockdrive/js/webpack.config.js +0 -68
  101. package/src/sockdrive/js/yarn.lock +0 -1808
  102. package/src/store/auth.ts +0 -115
  103. package/src/store/dos.ts +0 -305
  104. package/src/store/editor.ts +0 -61
  105. package/src/store/init.ts +0 -48
  106. package/src/store/storage.ts +0 -32
  107. package/src/store/ui.ts +0 -191
  108. package/src/store.tsx +0 -116
  109. package/src/ui.tsx +0 -140
  110. package/src/v8/changes.ts +0 -56
  111. package/src/v8/config.ts +0 -20
  112. package/src/v8/subscriptions.ts +0 -62
  113. package/src/vite-env.d.ts +0 -5
  114. package/src/window/dos/controls/keyboard.ts +0 -32
  115. package/src/window/dos/controls/keys.ts +0 -331
  116. package/src/window/dos/controls/mouse/mount.ts +0 -99
  117. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  118. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  119. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  120. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  121. package/src/window/dos/controls/mouse.ts +0 -21
  122. package/src/window/dos/dos-dhry2.tsx +0 -191
  123. package/src/window/dos/dos-runtime.tsx +0 -216
  124. package/src/window/dos/dos-window.tsx +0 -91
  125. package/src/window/dos/render/canvas.ts +0 -65
  126. package/src/window/dos/render/resize.ts +0 -31
  127. package/src/window/dos/render/webgl.ts +0 -173
  128. package/src/window/dos/sound/audio-node.ts +0 -148
  129. package/src/window/error-window.tsx +0 -9
  130. package/src/window/loading-window.tsx +0 -54
  131. package/src/window/prerun-window.tsx +0 -121
  132. package/src/window/select-window.tsx +0 -118
  133. package/src/window/window.css +0 -78
  134. package/src/window/window.tsx +0 -49
  135. package/src/ws/ws-sockdrive.ts +0 -123
  136. package/src/ws/ws-transport-layer.ts +0 -468
  137. package/tailwind.config.cjs +0 -48
  138. package/tsconfig.json +0 -32
  139. package/tsconfig.node.json +0 -9
  140. package/vite.config.ts +0 -25
@@ -1,89 +0,0 @@
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 && false;
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
- }
@@ -1,14 +0,0 @@
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
- }
@@ -1,44 +0,0 @@
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
- }
@@ -1,39 +0,0 @@
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
- }
@@ -1,244 +0,0 @@
1
- import { AnyAction } from "@reduxjs/toolkit";
2
- import { useDispatch, useSelector, useStore } from "react-redux";
3
- import { LockBadge } from "../components/lock";
4
- import { State, Store } from "../store";
5
- import { Frame, uiSlice } from "../store/ui";
6
- import { DisketteIcon } from "./diskette-icon";
7
- import { useEffect, useRef, useState } from "preact/hooks";
8
-
9
- export function ImageRenderingButton(props: {
10
- class?: string,
11
- }) {
12
- return <SidebarButton
13
- class={props.class}
14
- frame="image-rendering"
15
- action={uiSlice.actions.frameImageRendering()}
16
- >
17
- <svg xmlns="http://www.w3.org/2000/svg"
18
- fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
19
- class="w-full h-full">
20
- <path stroke-linecap="round"
21
- stroke-linejoin="round" d="M2.25 15.75l5.159-5.159a2.25 2.25 0
22
- 013.182 0l5.159 5.159m-1.5-1.5l1.409-1.409a2.25 2.25 0
23
- 013.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 001.5-1.5V6a1.5
24
- 1.5 0 00-1.5-1.5H3.75A1.5 1.5 0 002.25 6v12a1.5 1.5 0 001.5
25
- 1.5zm10.5-11.25h.008v.008h-.008V8.25zm.375 0a.375.375 0 11-.75
26
- 0 .375.375 0 01.75 0z" />
27
- </svg>
28
- </SidebarButton>;
29
- }
30
-
31
- export function QuickSaveButton(props: {
32
- class?: string,
33
- }) {
34
- const disabled = useSelector((state: State) => state.auth.account) === null && false;
35
- const action = disabled ?
36
- uiSlice.actions.modalLogin() :
37
- uiSlice.actions.frameQuickSave();
38
- return <SidebarButton
39
- class={props.class + (disabled ? " opacity-50" : "")}
40
- frame="quick-save"
41
- action={action}
42
- >
43
- <DisketteIcon />
44
- {disabled && <LockBadge />}
45
- </SidebarButton>;
46
- }
47
-
48
- export function FatDrivesButton(props: {
49
- class?: string,
50
- }) {
51
- return <SidebarButton
52
- class={props.class}
53
- frame="fat-drives"
54
- action={uiSlice.actions.frameFatDrives()}
55
- >
56
- <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
57
- stroke-width="1.5" stroke="currentColor" class="w-full h-full">
58
- <path stroke-linecap="round" stroke-linejoin="round" d="M5.25 14.25h13.5m-13.5
59
- 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3
60
- 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062
61
- 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0
62
- 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3
63
- 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
64
- </svg>
65
- </SidebarButton>;
66
- }
67
-
68
- export function DosboxConfButton(props: { class?: string }) {
69
- return <SidebarButton
70
- class={props.class}
71
- frame="editor-conf"
72
- action={uiSlice.actions.frameConf()}
73
- >
74
- <svg xmlns="http://www.w3.org/2000/svg"
75
- fill="none" viewBox="0 0 24 24"
76
- stroke-width="1.5"
77
- stroke="currentColor"
78
- class="w-full h-full">
79
- <path stroke-linecap="round"
80
- stroke-linejoin="round"
81
- d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125
82
- 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5
83
- 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504
84
- 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
85
- </svg>
86
- </SidebarButton>;
87
- }
88
-
89
- export function FsButton(props: {
90
- class?: string,
91
- }) {
92
- return <SidebarButton
93
- class={props.class}
94
- frame="editor-fs"
95
- action={uiSlice.actions.frameFs()}
96
- >
97
- <svg xmlns="http://www.w3.org/2000/svg" fill="none"
98
- viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-full h-full">
99
- <path stroke-linecap="round" stroke-linejoin="round" d="M21.75 17.25v-.228a4.5 4.5
100
- 0 00-.12-1.03l-2.268-9.64a3.375 3.375 0 00-3.285-2.602H7.923a3.375
101
- 3.375 0 00-3.285 2.602l-2.268 9.64a4.5 4.5 0 00-.12 1.03v.228m19.5 0a3 3
102
- 0 01-3 3H5.25a3 3 0 01-3-3m19.5 0a3 3 0 00-3-3H5.25a3 3 0 00-3 3m16.5
103
- 0h.008v.008h-.008v-.008zm-3 0h.008v.008h-.008v-.008z" />
104
- </svg>
105
- </SidebarButton>;
106
- }
107
-
108
- export function CyclesButton() {
109
- const cycles = Math.round(useSelector((state: State) => state.dos.stats.cyclesPerMs) / 1000);
110
- return <SidebarButton
111
- class="cycles"
112
- frame="stats"
113
- action={uiSlice.actions.frameStats()}>
114
- { cycles <= 0 && <><span>~</span><sup>KC</sup></> }
115
- { cycles > 0 && cycles <= 1000 && <><span>{cycles}</span><sup>KC</sup></> }
116
- { cycles > 0 && cycles > 1000 && <><span>{Math.round(cycles / 1000)}</span><sup><strong>K</strong>KC</sup></> }
117
- </SidebarButton>;
118
- }
119
-
120
- export function HddLed(props: {}) {
121
- const store: Store = useStore();
122
- const ref = useRef<HTMLDivElement>(null);
123
- const [state] = useState<{
124
- recv: number, enabled: boolean, delayLedTo: number,
125
- }>({ recv: 0, enabled: false, delayLedTo: 0 });
126
-
127
- useEffect(() => {
128
- if (ref.current) {
129
- const el = ref.current;
130
- el.classList.add("bg-base-300");
131
-
132
- const id = setInterval(() => {
133
- if (state.delayLedTo <= Date.now()) {
134
- const newRecv = store.getState().dos.stats.driveRecv;
135
- const newEnabled = state.recv !== newRecv;
136
- if (newEnabled !== state.enabled) {
137
- el.classList.remove("bg-base-300", "bg-green-300", "animate-led");
138
- if (newEnabled) {
139
- el.classList.add("bg-green-300", "animate-led");
140
- } else {
141
- el.classList.add("bg-base-300");
142
- }
143
- state.enabled = newEnabled;
144
- }
145
-
146
- if (newEnabled) {
147
- state.delayLedTo = Date.now() + 300 + Math.random() * 1500;
148
- } else {
149
- state.delayLedTo = 0;
150
- }
151
-
152
- state.recv = newRecv;
153
- }
154
- }, 150);
155
-
156
- return () => {
157
- el.classList.remove("bg-base-300", "bg-green-300", "animate-led");
158
- clearInterval(id);
159
- };
160
- }
161
- }, [ref, state]);
162
- const [on, setOn] = useState<boolean>(false);
163
- const [off, setOff] = useState<{ recv: number, timeoutId: number | null }>({
164
- recv: 0,
165
- timeoutId: null,
166
- });
167
- const statsRecv = useSelector((state: State) => state.dos.stats.driveRecv);
168
- if (off.recv !== statsRecv) {
169
- if (!on) {
170
- setOn(true);
171
- }
172
-
173
- if (off.timeoutId) {
174
- clearTimeout(off.timeoutId);
175
- }
176
-
177
- const id = setTimeout(() => {
178
- setOn(false);
179
- setOff({
180
- recv: statsRecv,
181
- timeoutId: null,
182
- });
183
- }, 1000);
184
-
185
- setOff({
186
- recv: statsRecv,
187
- timeoutId: id,
188
- });
189
- }
190
- return <div ref={ref} class="self-end mr-2 -mt-3 w-2 h-1"></div>;
191
- }
192
-
193
- export function SettingsButton(props: {
194
- class?: string,
195
- }) {
196
- return <SidebarButton
197
- class={props.class}
198
- action={uiSlice.actions.frameSettings()}
199
- frame="settings">
200
-
201
- <svg xmlns="http://www.w3.org/2000/svg" fill="none"
202
- viewBox="0 0 24 24" stroke-width="1.5"
203
- stroke="currentColor" class="w-full h-full">
204
- <path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55
205
- 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257
206
- 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26
207
- 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010
208
- .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298
209
- 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0
210
- 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55
211
- 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0
212
- 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0
213
- 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932
214
- 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0
215
- 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072
216
- 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
217
- <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
218
- </svg>
219
-
220
- </SidebarButton >;
221
- }
222
-
223
- export function SidebarButton(props: {
224
- class?: string,
225
- frame: Frame,
226
- action: AnyAction,
227
- children: any
228
- }) {
229
- const hightlight = useSelector((state: State) => state.ui.frame) === props.frame;
230
- const dispatch = useDispatch();
231
-
232
- function onClick() {
233
- if (hightlight) {
234
- dispatch(uiSlice.actions.frameNone());
235
- } else {
236
- dispatch(props.action);
237
- }
238
- }
239
-
240
- return <div class={"sidebar-button " + (hightlight ? "sidebar-highlight " : "") +
241
- props.class} onClick={onClick}>
242
- {props.children}
243
- </div>;
244
- }
@@ -1,47 +0,0 @@
1
- .jsdos-rso {
2
- .sidebar {
3
- @apply absolute left-0 top-0 h-full flex flex-col items-center py-2 z-10;
4
- background: linear-gradient(90deg, hsl(var(--b3)) 0%, hsl(var(--b2)) 100%);
5
- width: var(--sidebar-width);
6
-
7
- .contentbar {
8
- @apply flex-grow;
9
- }
10
-
11
- .sidebar-badge {
12
- @apply absolute right-0 bottom-0 w-3 h-3 rounded-full animate-pulse;
13
- background-color: hsl(var(--p));
14
- }
15
-
16
- .cycles {
17
- @apply text-xs overflow-hidden text-right w-full pr-2 mt-1 -mb-2 whitespace-nowrap opacity-50;
18
- color: hsl(var(--bc));
19
-
20
- &.higlight,
21
- &:hover {
22
- color: hsl(var(--af));
23
- }
24
- }
25
-
26
- .network-button {
27
- &.inactive {
28
- @apply opacity-50;
29
- }
30
- }
31
- }
32
-
33
- .sidebar-button {
34
- @apply cursor-pointer h-8 w-8 my-2 relative;
35
- color: hsl(var(--bc));
36
- }
37
-
38
- .sidebar-highlight,
39
- .sidebar-button:hover {
40
- color: hsl(var(--af));
41
- }
42
-
43
- .animate-led {
44
- animation: pulse 300ms cubic-bezier(0.4, 0, 0.6, 1) infinite;
45
- }
46
-
47
- }
@@ -1,30 +0,0 @@
1
- import { useSelector } from "react-redux";
2
- import { State } from "../store";
3
- import { AccountButton } from "./account-button";
4
- import { FullscreenButton } from "./fullscreen-button";
5
- import { NetworkButton } from "./network-button";
6
- import { CloudSaveButton } from "./cloud-save-button";
7
- import { DosboxConfButton, SettingsButton, CyclesButton, FsButton,
8
- FatDrivesButton, QuickSaveButton, ImageRenderingButton, HddLed } from "./sidebar-button";
9
-
10
- export function SideBar(props: {}) {
11
- const window = useSelector((state: State) => state.ui.window);
12
- const editor = useSelector((state: State) => state.ui.editor);
13
- const backend = useSelector((state: State) => state.dos.backend);
14
-
15
- return <div class="sidebar">
16
- {window === "run" && backend === "dosbox" && <CloudSaveButton />}
17
- {window === "run" && backend === "dosboxX" && <QuickSaveButton />}
18
- {window === "run" && <ImageRenderingButton />}
19
- {window === "run" && <NetworkButton />}
20
- {editor && window === "prerun" && <DosboxConfButton />}
21
- {editor && window === "prerun" && backend === "dosboxX" && <FatDrivesButton />}
22
- {editor && window === "run" && <FsButton />}
23
- <div class="contentbar"></div>
24
- {window === "run" && <FullscreenButton />}
25
- {window === "run" && <CyclesButton />}
26
- {window === "run" && <HddLed />}
27
- {(window === "prerun" || window === "run") && <SettingsButton />}
28
- {window !== "run" && <AccountButton />}
29
- </div>;
30
- };