js-dos 8.1.4 → 8.1.6

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 (141) hide show
  1. package/README.md +1 -1
  2. package/dist/emulators/emulators.js +2 -0
  3. package/dist/emulators/emulators.js.map +1 -0
  4. package/dist/emulators/types/build.d.ts +28 -0
  5. package/dist/emulators/types/dos/bundle/dos-bundle.d.ts +20 -0
  6. package/dist/emulators/types/dos/dosbox/ts/direct.d.ts +3 -0
  7. package/dist/emulators/types/dos/dosbox/ts/worker.d.ts +3 -0
  8. package/dist/emulators/types/emulators.d.ts +76 -0
  9. package/dist/emulators/types/http.d.ts +9 -0
  10. package/dist/emulators/types/impl/ci-impl.d.ts +29 -0
  11. package/dist/emulators/types/impl/emulators-impl.d.ts +26 -0
  12. package/dist/emulators/types/impl/modules.d.ts +38 -0
  13. package/dist/emulators/types/libzip/libzip.d.ts +16 -0
  14. package/dist/emulators/types/protocol/messages-queue.d.ts +8 -0
  15. package/dist/emulators/types/protocol/protocol.d.ts +128 -0
  16. package/dist/emulators/wdosbox-x.js +55 -0
  17. package/dist/emulators/wdosbox-x.js.symbols +8760 -0
  18. package/dist/emulators/wdosbox-x.wasm +0 -0
  19. package/dist/emulators/wdosbox.js +55 -0
  20. package/dist/emulators/wdosbox.js.symbols +3001 -0
  21. package/dist/emulators/wdosbox.wasm +0 -0
  22. package/dist/emulators/wlibzip.js +21 -0
  23. package/dist/emulators/wlibzip.js.symbols +268 -0
  24. package/dist/emulators/wlibzip.wasm +0 -0
  25. package/dist/js-dos.css +1 -0
  26. package/dist/js-dos.js +22 -0
  27. package/dist/js-dos.js.map +1 -0
  28. package/package.json +1 -1
  29. package/release.zip +0 -0
  30. package/.eslintrc.json +0 -43
  31. package/.github/workflows/build.yml +0 -51
  32. package/.gitmodules +0 -4
  33. package/index.html +0 -110
  34. package/postcss.config.cjs +0 -8
  35. package/src/app.css +0 -14
  36. package/src/base.css +0 -10
  37. package/src/components/checkbox.tsx +0 -41
  38. package/src/components/close-button.tsx +0 -17
  39. package/src/components/components.css +0 -28
  40. package/src/components/dos-option-checkbox.tsx +0 -94
  41. package/src/components/dos-option-select.tsx +0 -108
  42. package/src/components/dos-option-slider.tsx +0 -35
  43. package/src/components/error.tsx +0 -16
  44. package/src/components/loading.tsx +0 -26
  45. package/src/components/lock.tsx +0 -10
  46. package/src/components/select.tsx +0 -33
  47. package/src/components/slider.tsx +0 -69
  48. package/src/download-file.ts +0 -18
  49. package/src/frame/account-frame.tsx +0 -156
  50. package/src/frame/editor/defaults.ts +0 -419
  51. package/src/frame/editor/editor-conf-frame.tsx +0 -227
  52. package/src/frame/editor/editor-frame.css +0 -55
  53. package/src/frame/editor/editor-fs-frame.tsx +0 -314
  54. package/src/frame/fat-drives-frame.tsx +0 -199
  55. package/src/frame/frame.css +0 -119
  56. package/src/frame/frame.tsx +0 -34
  57. package/src/frame/image-rendering-frame.tsx +0 -8
  58. package/src/frame/network-frame.tsx +0 -157
  59. package/src/frame/quick-save-frame.tsx +0 -98
  60. package/src/frame/settings-frame.tsx +0 -14
  61. package/src/frame/stats-frame.tsx +0 -87
  62. package/src/host/bundle-storage.ts +0 -91
  63. package/src/host/fullscreen.ts +0 -35
  64. package/src/host/lcache.ts +0 -203
  65. package/src/host/lstorage.ts +0 -156
  66. package/src/i18n.ts +0 -185
  67. package/src/index.css +0 -7
  68. package/src/load.ts +0 -132
  69. package/src/login/login.css +0 -9
  70. package/src/login/login.tsx +0 -77
  71. package/src/main.tsx +0 -197
  72. package/src/public/types.ts +0 -45
  73. package/src/sidebar/account-button.tsx +0 -33
  74. package/src/sidebar/cloud-save-button.tsx +0 -89
  75. package/src/sidebar/diskette-icon.tsx +0 -14
  76. package/src/sidebar/fullscreen-button.tsx +0 -44
  77. package/src/sidebar/network-button.tsx +0 -39
  78. package/src/sidebar/sidebar-button.tsx +0 -244
  79. package/src/sidebar/sidebar.css +0 -47
  80. package/src/sidebar/sidebar.tsx +0 -30
  81. package/src/sockdrive/LICENSE +0 -674
  82. package/src/sockdrive/README.md +0 -45
  83. package/src/sockdrive/include/sockdrive.h +0 -23
  84. package/src/sockdrive/js/.eslintrc.json +0 -43
  85. package/src/sockdrive/js/package.json +0 -29
  86. package/src/sockdrive/js/src/fatfs/chains.js +0 -318
  87. package/src/sockdrive/js/src/fatfs/dir.js +0 -385
  88. package/src/sockdrive/js/src/fatfs/helpers.js +0 -210
  89. package/src/sockdrive/js/src/fatfs/index.js +0 -606
  90. package/src/sockdrive/js/src/fatfs/structs.js +0 -255
  91. package/src/sockdrive/js/src/fatfs/vol.js +0 -166
  92. package/src/sockdrive/js/src/sockdrive/cache.ts +0 -56
  93. package/src/sockdrive/js/src/sockdrive/drive.ts +0 -471
  94. package/src/sockdrive/js/src/sockdrive/lru.ts +0 -221
  95. package/src/sockdrive/js/src/sockdrive/types.ts +0 -14
  96. package/src/sockdrive/js/src/sockdrive-fat.d.ts +0 -64
  97. package/src/sockdrive/js/src/sockdrive-fat.ts +0 -226
  98. package/src/sockdrive/js/src/sockdrive-native.ts +0 -100
  99. package/src/sockdrive/js/src/test/test.ts +0 -289
  100. package/src/sockdrive/js/tsconfig.json +0 -11
  101. package/src/sockdrive/js/webpack.config.js +0 -68
  102. package/src/sockdrive/js/yarn.lock +0 -1808
  103. package/src/store/auth.ts +0 -115
  104. package/src/store/dos.ts +0 -305
  105. package/src/store/editor.ts +0 -61
  106. package/src/store/init.ts +0 -48
  107. package/src/store/storage.ts +0 -32
  108. package/src/store/ui.ts +0 -191
  109. package/src/store.tsx +0 -116
  110. package/src/ui.tsx +0 -140
  111. package/src/v8/changes.ts +0 -56
  112. package/src/v8/config.ts +0 -20
  113. package/src/v8/subscriptions.ts +0 -62
  114. package/src/vite-env.d.ts +0 -5
  115. package/src/window/dos/controls/keyboard.ts +0 -32
  116. package/src/window/dos/controls/keys.ts +0 -331
  117. package/src/window/dos/controls/mouse/mount.ts +0 -99
  118. package/src/window/dos/controls/mouse/mouse-locked.ts +0 -51
  119. package/src/window/dos/controls/mouse/mouse-not-locked.ts +0 -84
  120. package/src/window/dos/controls/mouse/mouse-swipe.ts +0 -57
  121. package/src/window/dos/controls/mouse/pointer.ts +0 -85
  122. package/src/window/dos/controls/mouse.ts +0 -21
  123. package/src/window/dos/dos-dhry2.tsx +0 -191
  124. package/src/window/dos/dos-runtime.tsx +0 -216
  125. package/src/window/dos/dos-window.tsx +0 -91
  126. package/src/window/dos/render/canvas.ts +0 -65
  127. package/src/window/dos/render/resize.ts +0 -31
  128. package/src/window/dos/render/webgl.ts +0 -173
  129. package/src/window/dos/sound/audio-node.ts +0 -148
  130. package/src/window/error-window.tsx +0 -9
  131. package/src/window/loading-window.tsx +0 -54
  132. package/src/window/prerun-window.tsx +0 -121
  133. package/src/window/select-window.tsx +0 -118
  134. package/src/window/window.css +0 -78
  135. package/src/window/window.tsx +0 -49
  136. package/src/ws/ws-sockdrive.ts +0 -123
  137. package/src/ws/ws-transport-layer.ts +0 -468
  138. package/tailwind.config.cjs +0 -48
  139. package/tsconfig.json +0 -32
  140. package/tsconfig.node.json +0 -9
  141. 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
- };