js-dos 0.80.25

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 (119) hide show
  1. package/.eslintrc.json +43 -0
  2. package/.github/workflows/build.yml +43 -0
  3. package/.gitmodules +4 -0
  4. package/README.md +24 -0
  5. package/index.html +106 -0
  6. package/package.json +48 -0
  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 +72 -0
  14. package/src/components/dos-option-select.tsx +94 -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 +155 -0
  23. package/src/frame/editor/defaults.ts +344 -0
  24. package/src/frame/editor/editor-conf-frame.tsx +42 -0
  25. package/src/frame/editor/editor-frame.css +55 -0
  26. package/src/frame/editor/editor-fs-frame.tsx +315 -0
  27. package/src/frame/frame.css +127 -0
  28. package/src/frame/frame.tsx +34 -0
  29. package/src/frame/host-cache-frame.tsx +124 -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 +95 -0
  33. package/src/frame/settings-frame.tsx +14 -0
  34. package/src/frame/stats-frame.tsx +82 -0
  35. package/src/host/bundle-storage.ts +91 -0
  36. package/src/host/fullscreen.ts +36 -0
  37. package/src/host/lcache.ts +203 -0
  38. package/src/host/lstorage.ts +156 -0
  39. package/src/i18n.ts +167 -0
  40. package/src/index.css +7 -0
  41. package/src/load.ts +139 -0
  42. package/src/login/login.css +9 -0
  43. package/src/login/login.tsx +77 -0
  44. package/src/main.tsx +195 -0
  45. package/src/non-serializable-store.ts +35 -0
  46. package/src/public/types.ts +39 -0
  47. package/src/sidebar/account-button.tsx +32 -0
  48. package/src/sidebar/cloud-save-button.tsx +89 -0
  49. package/src/sidebar/diskette-icon.tsx +14 -0
  50. package/src/sidebar/fullscreen-button.tsx +44 -0
  51. package/src/sidebar/network-button.tsx +39 -0
  52. package/src/sidebar/sidebar-button.tsx +243 -0
  53. package/src/sidebar/sidebar.css +47 -0
  54. package/src/sidebar/sidebar.tsx +30 -0
  55. package/src/sockdrive/LICENSE +674 -0
  56. package/src/sockdrive/README.md +22 -0
  57. package/src/sockdrive/SDL2/LRUCache11.hpp +240 -0
  58. package/src/sockdrive/SDL2/sockdrive.cpp +207 -0
  59. package/src/sockdrive/include/sockdrive.h +23 -0
  60. package/src/sockdrive/js/.eslintrc.json +43 -0
  61. package/src/sockdrive/js/README.md +70 -0
  62. package/src/sockdrive/js/package.json +29 -0
  63. package/src/sockdrive/js/src/fatfs/chains.js +318 -0
  64. package/src/sockdrive/js/src/fatfs/dir.js +385 -0
  65. package/src/sockdrive/js/src/fatfs/helpers.js +210 -0
  66. package/src/sockdrive/js/src/fatfs/index.js +606 -0
  67. package/src/sockdrive/js/src/fatfs/structs.js +255 -0
  68. package/src/sockdrive/js/src/fatfs/vol.js +166 -0
  69. package/src/sockdrive/js/src/sockdrive/cache.ts +133 -0
  70. package/src/sockdrive/js/src/sockdrive/drive.ts +364 -0
  71. package/src/sockdrive/js/src/sockdrive/lru.ts +221 -0
  72. package/src/sockdrive/js/src/sockdrive/types.ts +10 -0
  73. package/src/sockdrive/js/src/sockdrive-fat.d.ts +64 -0
  74. package/src/sockdrive/js/src/sockdrive-fat.ts +228 -0
  75. package/src/sockdrive/js/src/sockdrive-native.ts +98 -0
  76. package/src/sockdrive/js/src/test/test.ts +186 -0
  77. package/src/sockdrive/js/tsconfig.json +11 -0
  78. package/src/sockdrive/js/webpack.config.js +68 -0
  79. package/src/sockdrive/js/yarn.lock +1808 -0
  80. package/src/sockdrive/lz4/lz4.c +2773 -0
  81. package/src/sockdrive/lz4/lz4.h +862 -0
  82. package/src/store/auth.ts +104 -0
  83. package/src/store/dos.ts +284 -0
  84. package/src/store/editor.ts +59 -0
  85. package/src/store/storage.ts +30 -0
  86. package/src/store/ui.ts +183 -0
  87. package/src/store.ts +27 -0
  88. package/src/ui.tsx +103 -0
  89. package/src/v8/changes.ts +56 -0
  90. package/src/v8/config.ts +18 -0
  91. package/src/v8/subscriptions.ts +62 -0
  92. package/src/vite-env.d.ts +2 -0
  93. package/src/window/dos/controls/keyboard.ts +32 -0
  94. package/src/window/dos/controls/keys.ts +331 -0
  95. package/src/window/dos/controls/mouse/mount.ts +99 -0
  96. package/src/window/dos/controls/mouse/mouse-locked.ts +51 -0
  97. package/src/window/dos/controls/mouse/mouse-not-locked.ts +84 -0
  98. package/src/window/dos/controls/mouse/mouse-swipe.ts +57 -0
  99. package/src/window/dos/controls/mouse/pointer.ts +85 -0
  100. package/src/window/dos/controls/mouse.ts +21 -0
  101. package/src/window/dos/dos-dhry2.tsx +191 -0
  102. package/src/window/dos/dos-runtime.tsx +185 -0
  103. package/src/window/dos/dos-window.tsx +82 -0
  104. package/src/window/dos/render/canvas.ts +65 -0
  105. package/src/window/dos/render/resize.ts +31 -0
  106. package/src/window/dos/render/webgl.ts +173 -0
  107. package/src/window/dos/sound/audio-node.ts +148 -0
  108. package/src/window/error-window.tsx +9 -0
  109. package/src/window/loading-window.tsx +54 -0
  110. package/src/window/prerun-window.tsx +98 -0
  111. package/src/window/select-window.tsx +118 -0
  112. package/src/window/window.css +78 -0
  113. package/src/window/window.tsx +49 -0
  114. package/src/ws/ws-sockdrive.ts +102 -0
  115. package/src/ws/ws-transport-layer.ts +457 -0
  116. package/tailwind.config.cjs +48 -0
  117. package/tsconfig.json +32 -0
  118. package/tsconfig.node.json +9 -0
  119. package/vite.config.ts +22 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "env": {
3
+ "browser": true,
4
+ "es2021": true
5
+ },
6
+ "extends": [
7
+ "google"
8
+ ],
9
+ "parser": "@typescript-eslint/parser",
10
+ "parserOptions": {
11
+ "ecmaVersion": 12,
12
+ "sourceType": "module"
13
+ },
14
+ "plugins": [
15
+ "@typescript-eslint"
16
+ ],
17
+ "rules": {
18
+ "object-curly-spacing": [
19
+ "error",
20
+ "always"
21
+ ],
22
+ "require-jsdoc": "off",
23
+ "quotes": [
24
+ "error",
25
+ "double"
26
+ ],
27
+ "indent": [
28
+ "error",
29
+ 4,
30
+ {
31
+ "SwitchCase": 1,
32
+ "FunctionDeclaration": {
33
+ "parameters": "first"
34
+ }
35
+ }
36
+ ],
37
+ "max-len": [
38
+ "error",
39
+ 120
40
+ ]
41
+ },
42
+ "ignorePatterns": ["dist/**/*"]
43
+ }
@@ -0,0 +1,43 @@
1
+ name: Build
2
+
3
+ on:
4
+ push:
5
+ branches: [ 8.xx ]
6
+ tags:
7
+ - "v*.*.*"
8
+ pull_request:
9
+ branches: [ 8.xx ]
10
+
11
+ jobs:
12
+ build:
13
+ runs-on: ubuntu-latest
14
+
15
+ strategy:
16
+ matrix:
17
+ node-version: [18.x]
18
+
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ with:
22
+ submodules: 'recursive'
23
+ - name: build js-dos
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: ${{ matrix.node-version }}
27
+ registry-url: 'https://registry.npmjs.org'
28
+ cache: 'npm'
29
+ - run: npm install -g yarn
30
+ - run: yarn
31
+ - run: yarn run eslint . --ext ts,tsx --max-warnings 0
32
+ - run: mkdir -p public/emulators && cp -rv node_modules/emulators/dist/* public/emulators
33
+ - run: NODE_ENV=production yarn run vite build --base /latest --sourcemap true --minify terser
34
+ - name: publish
35
+ if: startsWith(github.ref, 'refs/tags/')
36
+ run: npm publish --tag beta
37
+ env:
38
+ NODE_AUTH_TOKEN: ${{secrets.NODE_AUTH_TOKEN}}
39
+ - name: upload
40
+ uses: actions/upload-artifact@v3.0.0
41
+ with:
42
+ name: 'dist'
43
+ path: 'dist'
package/.gitmodules ADDED
@@ -0,0 +1,4 @@
1
+ [submodule "src/sockdrive"]
2
+ path = src/sockdrive
3
+ url = git@github.com:makevm/sockdrive.git
4
+ branch = main
package/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # js-dos v8
2
+ [![Build](https://github.com/caiiiycuk/js-dos/actions/workflows/build.yml/badge.svg?branch=8.xx)](https://github.com/caiiiycuk/js-dos/actions/workflows/build.yml)
3
+
4
+ The **next** major version of js-dos.
5
+
6
+ **Not production ready. [Please use 7.xx for production.](https://github.com/caiiiycuk/js-dos/tree/7.xx)**
7
+
8
+ [![Watch the video](https://github.com/caiiiycuk/js-dos/assets/1727152/a2b481cb-43b1-44aa-8b71-2181d351bb1a)](https://youtu.be/lhFrAe5YrJE)
9
+
10
+ # Requirments
11
+
12
+ You need to put `emulators@beta` into `public/emulators`.
13
+
14
+ ```
15
+ cp -rv node_modules/emulators/dist/* public/emulators
16
+ ```
17
+
18
+ # Deployment
19
+
20
+ ```
21
+ yarn run vite build --base /latest --sourcemap true --minify terser && \
22
+ aws s3 --endpoint-url=https://storage.yandexcloud.net sync --acl public-read \
23
+ dist s3://jsdos/latest --delete
24
+ ```
package/index.html ADDED
@@ -0,0 +1,106 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>js-dos 8.xx</title>
8
+ <style>
9
+ html,
10
+ body {
11
+ width: 100%;
12
+ height: 100%;
13
+ }
14
+ </style>
15
+ </head>
16
+
17
+ <body>
18
+ <div id="app"></div>
19
+ <script type="module" src="/src/main.tsx">
20
+ </script>
21
+ <script>
22
+ const params = new URLSearchParams(location.search);
23
+ document.addEventListener("DOMContentLoaded", () => {
24
+ /* eslint-disable max-len */
25
+ /* eslint-enable max-len */
26
+ const props = Dos(document.getElementById("app"),
27
+ {
28
+ // url: decodeURIComponent("https%3A%2F%2Fcdn.dos.zone%2Fcustom%2Fdos%2Fdoom_dm.jsdos"),
29
+ // url: decodeURIComponent("https%3A%2F%2Fcdn.dos.zone%2Fcustom%2Fdos%2Fhomm2_netbios.jsdos"),
30
+ // url: "https://cdn.dos.zone/original/2X/2/24b00b14f118580763440ecaddcc948f8cb94f14.jsdos", // digger
31
+ // url: "https://cdn.dos.zone/custom/dos/doom.jsdos",
32
+ // url: "https://cdn.dos.zone/custom/dos/duke3d_ipx.jsdos",
33
+ // url: "https://br.cdn.dos.zone/ipx/duke3d/duke3d_ipx.jsdos",
34
+ // url: "https://br.cdn.dos.zone/ipx/doom_dm/doom_dm.jsdos",
35
+ // url: "https://cdn.dos.zone/original/2X/b/b4b5275904d86a4ab8a20917b2b7e34f0df47bf7.jsdos", // dhry2
36
+ // url: "https://cdn.dos.zone/original/2X/7/744842062905f72648a4d492ccc2526d039b3702.jsdos", // sim-city
37
+ // dosboxConf: diabloConf,
38
+ pathPrefix: "/emulators/",
39
+ server: params.get("server"),
40
+ room: params.get("room"),
41
+ //backendHardware: (backend) => {
42
+ // console.log("Hardware backend for", backend);
43
+ // return Promise.resolve("ws://127.0.0.1:8080");
44
+ //},
45
+ onEvent: (event) => {
46
+ console.log("Event", event)
47
+ if (event === "ci-ready") {
48
+ // props.setFrame("network");
49
+ // props.setFullScreen(true);
50
+ }
51
+ },
52
+ });
53
+ });
54
+
55
+ const diabloConf = `
56
+ [sdl]
57
+ autolock=false
58
+ mouse_emulation=integration
59
+
60
+ [dosbox]
61
+ title=Windows 95
62
+ memsize=128
63
+
64
+ [video]
65
+ vmemsize=8
66
+ vesa modelist width limit=0
67
+ vesa modelist height limit=0
68
+
69
+ [dos]
70
+ ver=7.1
71
+ hard drive data rate limit=0
72
+ floppy drive data rate limit=0
73
+
74
+ [cpu]
75
+ cputype=pentium_mmx
76
+ core=auto
77
+ integration device=true
78
+
79
+ [sblaster]
80
+ sbtype=sb16vibra
81
+
82
+ [fdc, primary]
83
+ int13fakev86io=true
84
+
85
+ [ide, primary]
86
+ int13fakeio=true
87
+ int13fakev86io=true
88
+
89
+ [ide, secondary]
90
+ int13fakeio=true
91
+ int13fakev86io=true
92
+ cd-rom insertion delay=4000
93
+
94
+ [render]
95
+ scaler=none
96
+
97
+ [autoexec]
98
+ echo off
99
+ imgmount 2 sockdrive wss://backend.make-vm.com:8001 dos.zone diablo_109_c
100
+ imgmount 3 sockdrive wss://backend.make-vm.com:8001 dos.zone diablo_109_d
101
+ boot c:
102
+ `;
103
+ </script>
104
+ </body>
105
+
106
+ </html>
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "js-dos",
3
+ "version": "0.80.25",
4
+ "description": "Full-featured DOS player with multiple emulator backends",
5
+ "type": "module",
6
+ "keywords": [
7
+ "js-dos",
8
+ "dos",
9
+ "api",
10
+ "browser",
11
+ "dosbox",
12
+ "emulators",
13
+ "webassembly"
14
+ ],
15
+ "author": "Alexander Guryanov (aka caiiiycuk)",
16
+ "license": "GPL-2.0",
17
+ "bugs": {
18
+ "url": "https://github.com/caiiiycuk/js-dos/issues"
19
+ },
20
+ "homepage": "https://js-dos.com",
21
+ "scripts": {
22
+ "dev": "vite",
23
+ "build": "tsc && vite build",
24
+ "preview": "vite preview"
25
+ },
26
+ "dependencies": {
27
+ "@reduxjs/toolkit": "^1.9.7",
28
+ "preact": "^10.19.3",
29
+ "react-checkbox-tree": "^1.8.0",
30
+ "react-redux": "^8.1.3"
31
+ },
32
+ "devDependencies": {
33
+ "@preact/preset-vite": "^2.8.1",
34
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
35
+ "@typescript-eslint/parser": "^6.20.0",
36
+ "autoprefixer": "^10.4.17",
37
+ "daisyui": "^3.9.3",
38
+ "emulators": "0.80.25",
39
+ "eslint": "^8.56.0",
40
+ "eslint-config-google": "^0.14.0",
41
+ "postcss": "^8.4.33",
42
+ "postcss-import": "^16.0.0",
43
+ "tailwindcss": "^3.4.1",
44
+ "terser": "^5.27.0",
45
+ "typescript": "^5.3.3",
46
+ "vite": "^5.0.12"
47
+ }
48
+ }
@@ -0,0 +1,8 @@
1
+ module.exports = {
2
+ plugins: {
3
+ 'postcss-import': {},
4
+ 'tailwindcss/nesting': {},
5
+ tailwindcss: {},
6
+ autoprefixer: {},
7
+ },
8
+ }
package/src/app.css ADDED
@@ -0,0 +1,14 @@
1
+ .jsdos-rso {
2
+ @apply h-full;
3
+ background: hsl(var(--pc));
4
+
5
+ .jsdos-fullscreen-workaround {
6
+ position: fixed !important;
7
+ left: 0;
8
+ top: 0;
9
+ bottom: 0;
10
+ right: 0;
11
+ background: black;
12
+ z-index: 999;
13
+ }
14
+ }
package/src/base.css ADDED
@@ -0,0 +1,10 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --sidebar-width: 3rem;
8
+ /* w-12 */
9
+ }
10
+ }
@@ -0,0 +1,41 @@
1
+ import { useEffect, useRef } from "preact/hooks";
2
+
3
+ export function Checkbox(props: {
4
+ class?: string,
5
+ toggleClass?: string,
6
+ label: string,
7
+ checked?: boolean,
8
+ onChange?: (value: boolean) => void,
9
+ disabled?: boolean,
10
+ intermediate?: boolean,
11
+ }) {
12
+ const ref = useRef<HTMLInputElement>(null);
13
+
14
+ useEffect(() => {
15
+ if (ref === null || ref.current === null) {
16
+ return;
17
+ }
18
+
19
+ (ref.current as any).indeterminate = props.intermediate;
20
+ }, [ref, props.intermediate]);
21
+
22
+ function onChange() {
23
+ if (props.onChange) {
24
+ props.onChange(!(props.checked === true));
25
+ }
26
+ }
27
+
28
+ return <div className={props.class + " form-control option"}
29
+ onClick={onChange}>
30
+ <label className="label cursor-pointer">
31
+ <span className="label-text mr-6">{props.label}</span>
32
+ <input
33
+ ref={ref}
34
+ checked={props.checked === true}
35
+ type="checkbox"
36
+ className={ "toggle " + (props.checked ? " toggle-primary " : "") +
37
+ props.toggleClass }
38
+ disabled={props.disabled === true} />
39
+ </label>
40
+ </div>;
41
+ }
@@ -0,0 +1,17 @@
1
+ export function CloseButton(props: {
2
+ onClose: () => void
3
+ class?: string,
4
+ }) {
5
+ return <div class={ "text-gray-400 hover:text-gray-600 btn " +
6
+ props.class } onClick={props.onClose}>
7
+ <svg xmlns="http://www.w3.org/2000/svg"
8
+ class="w-full h-full"
9
+ fill="none"
10
+ viewBox="0 0 24 24"
11
+ stroke="currentColor"
12
+ stroke-width="2">
13
+ <path stroke-linecap="round" stroke-linejoin="round"
14
+ d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" />
15
+ </svg>
16
+ </div>;
17
+ }
@@ -0,0 +1,28 @@
1
+ .jsdos-rso {
2
+ select {
3
+ @apply select select-bordered;
4
+ }
5
+
6
+ .slider {
7
+ @apply flex flex-row items-center;
8
+
9
+ .label {
10
+ @apply mr-4 w-min;
11
+ }
12
+
13
+ .touch {
14
+ @apply cursor-pointer h-16 relative flex-grow flex flex-row items-center;
15
+
16
+ .bg {
17
+ @apply w-full h-2 rounded-full;
18
+ background-color: hsl(var(--b2));
19
+ }
20
+
21
+ .point {
22
+ @apply absolute h-6 w-6 rounded-full;
23
+ background-color: hsl(var(--bc));
24
+ }
25
+ }
26
+
27
+ }
28
+ }
@@ -0,0 +1,72 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { useT } from "../i18n";
3
+ import { State } from "../store";
4
+ import { dosSlice } from "../store/dos";
5
+ import { uiSlice } from "../store/ui";
6
+ import { Checkbox } from "./checkbox";
7
+ import { nonSerializableStore } from "../non-serializable-store";
8
+
9
+ export function Editor() {
10
+ const t = useT();
11
+ const dispatch = useDispatch();
12
+ const editor = useSelector((state: State) => state.ui.editor);
13
+ return <Checkbox
14
+ class="mt-4"
15
+ label={t("editor")}
16
+ checked={editor}
17
+ onChange={(e) => dispatch(uiSlice.actions.setEditor(e))}
18
+ />;
19
+ }
20
+
21
+ export function MouseCapture() {
22
+ const t = useT();
23
+ const dispatch = useDispatch();
24
+ const lock = useSelector((state: State) => state.dos.mouseCapture);
25
+ return <Checkbox
26
+ class="mt-4"
27
+ label={t("mouse_lock")}
28
+ checked={lock}
29
+ onChange={(l) => dispatch(dosSlice.actions.mouseCapture(l))}
30
+ />;
31
+ }
32
+
33
+ export function PauseCheckbox() {
34
+ const t = useT();
35
+ const dispatch = useDispatch();
36
+ const paused = useSelector((state: State) => state.dos.paused);
37
+ const disabled = useSelector((state: State) => state.ui.window) !== "run";
38
+ return <Checkbox
39
+ class="mt-4"
40
+ label={t("pause")}
41
+ checked={paused}
42
+ disabled={disabled}
43
+ onChange={(p) => dispatch(dosSlice.actions.paused(p))}
44
+ />;
45
+ }
46
+
47
+ export function WorkerCheckbox() {
48
+ const t = useT();
49
+ const dispatch = useDispatch();
50
+ const worker = useSelector((state: State) => state.dos.worker);
51
+ const hardware = useSelector((state: State) => state.dos.backendHardware);
52
+ const disabled = useSelector((state: State) => state.ui.window) === "run";
53
+ return hardware && nonSerializableStore.options.backendHardware ? null : <Checkbox
54
+ class="mt-4"
55
+ label={t("worker")}
56
+ checked={worker}
57
+ disabled={disabled}
58
+ onChange={(w) => dispatch(dosSlice.actions.dosWorker(w))}
59
+ />;
60
+ }
61
+
62
+ export function HardwareCheckbox() {
63
+ const t = useT();
64
+ const dispatch = useDispatch();
65
+ const hardware = useSelector((state: State) => state.dos.backendHardware);
66
+ return nonSerializableStore.options.backendHardware ? <Checkbox
67
+ class="mt-4"
68
+ label={t("hardware")}
69
+ checked={hardware}
70
+ onChange={(h) => dispatch(dosSlice.actions.dosBackendHardware(h))}
71
+ /> : null;
72
+ }
@@ -0,0 +1,94 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { useT } from "../i18n";
3
+ import { State } from "../store";
4
+ import { Select } from "./select";
5
+ import { AnyAction } from "@reduxjs/toolkit";
6
+ import {
7
+ Backend, BackendValues, dosSlice, ImageRendering, ImageRenderingValues, RenderAspect, RenderAspectValues,
8
+ RenderBackend, RenderBackendValues,
9
+ } from "../store/dos";
10
+ import { ThemeValues, Theme, uiSlice } from "../store/ui";
11
+ import { lStorage } from "../host/lstorage";
12
+
13
+ export function BackendSelect() {
14
+ const locked = useSelector((state: State) => state.dos.backendLocked);
15
+ return <OptionSelect
16
+ label="emulation_backend"
17
+ values={[...BackendValues]}
18
+ disabled={locked}
19
+ selector={(state: State) => state.dos.backend}
20
+ dispatch={(newValue: Backend) => {
21
+ lStorage.setItem("backend", newValue);
22
+ return dosSlice.actions.dosBackend(newValue);
23
+ }}
24
+ />;
25
+ }
26
+
27
+ export function RenderSelect() {
28
+ const disabled = useSelector((state: State) => state.ui.window) === "run";
29
+ return <OptionSelect
30
+ label="render_backend"
31
+ values={[...RenderBackendValues]}
32
+ disabled={disabled}
33
+ selector={(state: State) => state.dos.renderBackend}
34
+ dispatch={(newValue: RenderBackend) => dosSlice.actions.renderBackend(newValue)}
35
+ />;
36
+ }
37
+
38
+ export function RenderAspectSelect(props: { multiline?: boolean }) {
39
+ return <OptionSelect
40
+ label="render_aspect"
41
+ multiline={props.multiline}
42
+ values={[...RenderAspectValues]}
43
+ selector={(state: State) => state.dos.renderAspect}
44
+ dispatch={(newValue: RenderAspect) => dosSlice.actions.renderAspect(newValue)}
45
+ />;
46
+ }
47
+
48
+ export function ImageRenderingSelect(props: { multiline?: boolean }) {
49
+ return <OptionSelect
50
+ label="image_rendering"
51
+ multiline={props.multiline}
52
+ values={[...ImageRenderingValues]}
53
+ selector={(state: State) => state.dos.imageRendering}
54
+ dispatch={(newValue: ImageRendering) => dosSlice.actions.imageRendering(newValue)}
55
+ />;
56
+ }
57
+
58
+ export function ThemeSelect(props: { class?: string, multiline?: boolean }) {
59
+ return <OptionSelect
60
+ class={props.class}
61
+ label="theme"
62
+ values={[...ThemeValues]}
63
+ selector={(state: State) => state.ui.theme}
64
+ dispatch={(newValue: Theme) => uiSlice.actions.theme(newValue)}
65
+ multiline={props.multiline}
66
+ />;
67
+ }
68
+
69
+ function OptionSelect<T>(props: {
70
+ class?: string,
71
+ label: string,
72
+ values: string[]
73
+ selector: (state: State) => T,
74
+ dispatch: (newValue: T) => AnyAction;
75
+ disabled?: boolean,
76
+ multiline?: boolean,
77
+ }) {
78
+ const t = useT();
79
+ const value = useSelector(props.selector);
80
+ const dispatch = useDispatch();
81
+
82
+ function onBackend(newValue: T) {
83
+ dispatch(props.dispatch(newValue));
84
+ }
85
+ return <Select
86
+ class={"mt-4 " + props.class}
87
+ disabled={props.disabled}
88
+ multiline={props.multiline}
89
+ label={t(props.label)}
90
+ selected={value as string}
91
+ values={props.values}
92
+ onSelect={onBackend as any} />;
93
+ }
94
+
@@ -0,0 +1,35 @@
1
+ import { useDispatch, useSelector } from "react-redux";
2
+ import { useT } from "../i18n";
3
+ import { dosSlice } from "../store/dos";
4
+ import { Slider } from "./slider";
5
+ import { State } from "../store";
6
+
7
+ export function MouseSensitiviySlider(props: {
8
+ class?: string,
9
+ }) {
10
+ const t = useT();
11
+ const sensitivity = useSelector((state: State) => state.dos.mouseSensitivity);
12
+ const dispatch = useDispatch();
13
+
14
+ return <Slider
15
+ class={"mt-4 " + props.class}
16
+ label={t("mouse_sensitivity")}
17
+ value={sensitivity}
18
+ onChange={(value) => dispatch(dosSlice.actions.mouseSensitivity(value)) }
19
+ />;
20
+ }
21
+
22
+ export function VolumeSlider(props: {
23
+ class?: string,
24
+ }) {
25
+ const t = useT();
26
+ const volume = useSelector((state: State) => state.dos.volume);
27
+ const dispatch = useDispatch();
28
+
29
+ return <Slider
30
+ class={props.class}
31
+ label={t("volume")}
32
+ value={volume}
33
+ onChange={(value) => dispatch(dosSlice.actions.volume(value)) }
34
+ />;
35
+ }
@@ -0,0 +1,16 @@
1
+ import { useT } from "../i18n";
2
+
3
+ export function Error(props: {
4
+ error?: string | null,
5
+ onSkip?: () => void,
6
+ }) {
7
+ const t = useT();
8
+ const error = props.error ?? "Unexpected error";
9
+
10
+ return <div class="flex-grow flex flex-col items-center justify-center px-8 m-auto">
11
+ <div class="text-2xl text-center">{t("error")}</div>
12
+ <div class="text-red-400 mt-8 text-2xl text-center">"{error}"</div>
13
+ <div class="mt-8 text-sm text-center">{t("consult_logs")}</div>
14
+ { props.onSkip && <button class="mt-8 btn-primary" onClick={props.onSkip}>{t("skip")}</button> }
15
+ </div>;
16
+ }
@@ -0,0 +1,26 @@
1
+ export function Loading(props: {
2
+ head: string,
3
+ message: string,
4
+ }) {
5
+ const { head, message } = props;
6
+
7
+ return <div class="flex flex-col items-center justify-center frame-color px-8">
8
+ <div class="text-2xl text-center">{head}</div>
9
+ <div class="mt-2 text-center">{message}</div>
10
+ </div>;
11
+ }
12
+
13
+ export function formatSize(size: number) {
14
+ if (size < 1024) {
15
+ return size + "b";
16
+ }
17
+
18
+ size /= 1024;
19
+
20
+ if (size < 1024) {
21
+ return Math.round(size) + "kb";
22
+ }
23
+
24
+ size /= 1024;
25
+ return Math.round(size * 10) / 10 + "mb";
26
+ }
@@ -0,0 +1,10 @@
1
+ export function LockBadge(props: {
2
+ class?: string,
3
+ }) {
4
+ return <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"
5
+ class={ props.class ?? "absolute left-0 top-0 -ml-1 -mt-1 text-error w-4 h-4" }>
6
+ <path fill-rule="evenodd" d="M12 1.5a5.25 5.25 0 00-5.25 5.25v3a3 3 0 00-3 3v6.75a3 3 0 003
7
+ 3h10.5a3 3 0 003-3v-6.75a3 3 0 00-3-3v-3c0-2.9-2.35-5.25-5.25-5.25zm3.75
8
+ 8.25v-3a3.75 3.75 0 10-7.5 0v3h7.5z" clip-rule="evenodd" />
9
+ </svg>;
10
+ }