@swf2es/desktop 0.0.0-stage → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +132 -2
- package/dist/launch/electron.d.ts +14 -0
- package/dist/launch/electron.d.ts.map +1 -0
- package/dist/launch/electron.js +40 -0
- package/dist/launch/electron.js.map +1 -0
- package/dist/launch/launch.d.ts +3 -0
- package/dist/launch/launch.d.ts.map +1 -0
- package/dist/launch/launch.js +69 -0
- package/dist/launch/launch.js.map +1 -0
- package/dist/main/addresses.d.ts +7 -0
- package/dist/main/addresses.d.ts.map +1 -0
- package/dist/main/addresses.js +155 -0
- package/dist/main/addresses.js.map +1 -0
- package/dist/main/air.d.ts +71 -0
- package/dist/main/air.d.ts.map +1 -0
- package/dist/main/air.js +216 -0
- package/dist/main/air.js.map +1 -0
- package/dist/main/connections.d.ts +38 -0
- package/dist/main/connections.d.ts.map +1 -0
- package/dist/main/connections.js +103 -0
- package/dist/main/connections.js.map +1 -0
- package/dist/main/decompress.d.ts +51 -0
- package/dist/main/decompress.d.ts.map +1 -0
- package/dist/main/decompress.js +184 -0
- package/dist/main/decompress.js.map +1 -0
- package/dist/main/files.d.ts +9 -0
- package/dist/main/files.d.ts.map +1 -0
- package/dist/main/files.js +120 -0
- package/dist/main/files.js.map +1 -0
- package/dist/main/main.d.ts +2 -0
- package/dist/main/main.d.ts.map +1 -0
- package/dist/main/main.js +979 -0
- package/dist/main/main.js.map +1 -0
- package/dist/main/network.d.ts +182 -0
- package/dist/main/network.d.ts.map +1 -0
- package/dist/main/network.js +909 -0
- package/dist/main/network.js.map +1 -0
- package/dist/main/policy.d.ts +103 -0
- package/dist/main/policy.d.ts.map +1 -0
- package/dist/main/policy.js +481 -0
- package/dist/main/policy.js.map +1 -0
- package/dist/main/protocol.d.ts +14 -0
- package/dist/main/protocol.d.ts.map +1 -0
- package/dist/main/protocol.js +216 -0
- package/dist/main/protocol.js.map +1 -0
- package/dist/main/sandbox.d.ts +67 -0
- package/dist/main/sandbox.d.ts.map +1 -0
- package/dist/main/sandbox.js +182 -0
- package/dist/main/sandbox.js.map +1 -0
- package/dist/main/settings.d.ts +37 -0
- package/dist/main/settings.d.ts.map +1 -0
- package/dist/main/settings.js +88 -0
- package/dist/main/settings.js.map +1 -0
- package/dist/main/sockets.d.ts +10 -0
- package/dist/main/sockets.d.ts.map +1 -0
- package/dist/main/sockets.js +71 -0
- package/dist/main/sockets.js.map +1 -0
- package/dist/preload/preload.cjs +91 -0
- package/dist/preload/preload.cjs.map +1 -0
- package/dist/preload/preload.d.cts +2 -0
- package/dist/preload/preload.d.cts.map +1 -0
- package/dist/preload/prompt.cjs +12 -0
- package/dist/preload/prompt.cjs.map +1 -0
- package/dist/preload/prompt.d.cts +2 -0
- package/dist/preload/prompt.d.cts.map +1 -0
- package/dist/renderer/air.d.ts +14 -0
- package/dist/renderer/air.d.ts.map +1 -0
- package/dist/renderer/air.js +83 -0
- package/dist/renderer/air.js.map +1 -0
- package/dist/renderer/files.d.ts +4 -0
- package/dist/renderer/files.d.ts.map +1 -0
- package/dist/renderer/files.js +58 -0
- package/dist/renderer/files.js.map +1 -0
- package/dist/renderer/index.d.ts +7 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +126 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/network.d.ts +6 -0
- package/dist/renderer/network.d.ts.map +1 -0
- package/dist/renderer/network.js +39 -0
- package/dist/renderer/network.js.map +1 -0
- package/dist/renderer/open-url.d.ts +10 -0
- package/dist/renderer/open-url.d.ts.map +1 -0
- package/dist/renderer/open-url.js +38 -0
- package/dist/renderer/open-url.js.map +1 -0
- package/dist/renderer/sockets.d.ts +4 -0
- package/dist/renderer/sockets.d.ts.map +1 -0
- package/dist/renderer/sockets.js +36 -0
- package/dist/renderer/sockets.js.map +1 -0
- package/dist/renderer/stage3d.d.ts +3 -0
- package/dist/renderer/stage3d.d.ts.map +1 -0
- package/dist/renderer/stage3d.js +26 -0
- package/dist/renderer/stage3d.js.map +1 -0
- package/dist/shared/api.d.ts +205 -0
- package/dist/shared/api.d.ts.map +1 -0
- package/dist/shared/api.js +5 -0
- package/dist/shared/api.js.map +1 -0
- package/package.json +46 -3
- package/src/launch/electron.ts +44 -0
- package/src/launch/launch.ts +72 -0
- package/src/launch/tsconfig.json +14 -0
- package/src/main/addresses.ts +184 -0
- package/src/main/air.ts +275 -0
- package/src/main/connections.ts +125 -0
- package/src/main/decompress.ts +219 -0
- package/src/main/files.ts +147 -0
- package/src/main/main.ts +1146 -0
- package/src/main/network.ts +1205 -0
- package/src/main/policy.ts +630 -0
- package/src/main/protocol.ts +237 -0
- package/src/main/sandbox.ts +213 -0
- package/src/main/settings.ts +117 -0
- package/src/main/sockets.ts +81 -0
- package/src/main/tsconfig.json +15 -0
- package/src/preload/preload.cts +110 -0
- package/src/preload/prompt.cts +11 -0
- package/src/preload/tsconfig.json +12 -0
- package/src/renderer/air.ts +100 -0
- package/src/renderer/files.ts +65 -0
- package/src/renderer/index.ts +145 -0
- package/src/renderer/network.ts +56 -0
- package/src/renderer/open-url.ts +50 -0
- package/src/renderer/sockets.ts +42 -0
- package/src/renderer/stage3d.ts +27 -0
- package/src/renderer/tsconfig.json +17 -0
- package/src/shared/api.ts +204 -0
- package/src/shared/tsconfig.json +11 -0
- package/static/icon.png +0 -0
- package/static/index.html +22 -0
- package/static/open-url.html +21 -0
- package/static/style.css +96 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// What the shell gives the page, and all it gives: the preload puts it on
|
|
2
|
+
// window.swf2esDesktop. The renderer knows the shell only through it, so
|
|
3
|
+
// another shell (Tauri, later) plays the same page by giving the same API.
|
|
4
|
+
|
|
5
|
+
/** Flash's sandboxes, as Security.sandboxType names them, and AIR's application sandbox. */
|
|
6
|
+
export type SandboxType = "localWithFile" | "localWithNetwork" | "remote" | "application";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* An AIR application the shell opened by its descriptor, as adl runs one:
|
|
10
|
+
* what NativeApplication and File see of it.
|
|
11
|
+
*/
|
|
12
|
+
export interface AirLaunch {
|
|
13
|
+
/** The descriptor's XML and its id. */
|
|
14
|
+
descriptor: string;
|
|
15
|
+
id: string;
|
|
16
|
+
/** What followed `--` on the command line. */
|
|
17
|
+
arguments: string[];
|
|
18
|
+
/** Where the shell was started, a native path. */
|
|
19
|
+
currentDirectory: string;
|
|
20
|
+
/** The system's path separator. */
|
|
21
|
+
separator: string;
|
|
22
|
+
/** The directories AIR names: the application's (the descriptor's) and its storage's among them. */
|
|
23
|
+
directories: {
|
|
24
|
+
application: string;
|
|
25
|
+
applicationStorage: string;
|
|
26
|
+
user: string;
|
|
27
|
+
documents: string;
|
|
28
|
+
desktop: string;
|
|
29
|
+
cache: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** What is at a path, as the player's FileStat has it. */
|
|
34
|
+
export interface AirFileStat {
|
|
35
|
+
directory: boolean;
|
|
36
|
+
size: number;
|
|
37
|
+
modified: number;
|
|
38
|
+
created: number;
|
|
39
|
+
hidden?: boolean;
|
|
40
|
+
symbolicLink?: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The window as NativeWindow reads it: bounds frame included, and the content's corner in it. */
|
|
44
|
+
export interface AirWindowState {
|
|
45
|
+
bounds: { x: number; y: number; width: number; height: number };
|
|
46
|
+
contentOffset: { x: number; y: number };
|
|
47
|
+
title: string;
|
|
48
|
+
displayState: string;
|
|
49
|
+
active: boolean;
|
|
50
|
+
visible: boolean;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* An AIR application's own reach, only while one the user opened plays:
|
|
55
|
+
* the file system, read and written synchronously as File does, and the
|
|
56
|
+
* window.
|
|
57
|
+
*/
|
|
58
|
+
export interface DesktopAir {
|
|
59
|
+
stat(path: string): AirFileStat | null;
|
|
60
|
+
list(path: string): string[] | null;
|
|
61
|
+
read(path: string): Promise<Uint8Array | null>;
|
|
62
|
+
/** A file's bytes at once, as FileStream's open reads them; null where none can be read. */
|
|
63
|
+
readSync(path: string): Uint8Array | null;
|
|
64
|
+
/** EncryptedLocalStore's items, at once, as the player's EncryptedStoreHost has them. */
|
|
65
|
+
getItem(name: string): Uint8Array | null;
|
|
66
|
+
setItem(name: string, bytes: Uint8Array): void;
|
|
67
|
+
removeItem(name: string): void;
|
|
68
|
+
resetItems(): void;
|
|
69
|
+
/** FileStream's writes and File's changes, at once, as FileSystemHost's; false where they fail. */
|
|
70
|
+
writeSync(path: string, bytes: Uint8Array, offset: number, length: number): boolean;
|
|
71
|
+
createDirectory(path: string): boolean;
|
|
72
|
+
remove(path: string): boolean;
|
|
73
|
+
move(from: string, to: string): boolean;
|
|
74
|
+
window(): AirWindowState;
|
|
75
|
+
setBounds(bounds: { x: number; y: number; width: number; height: number }): void;
|
|
76
|
+
setTitle(title: string): void;
|
|
77
|
+
minimize(): void;
|
|
78
|
+
maximize(): void;
|
|
79
|
+
restore(): void;
|
|
80
|
+
activate(): void;
|
|
81
|
+
setVisible(visible: boolean): void;
|
|
82
|
+
close(): void;
|
|
83
|
+
exit(code: number): void;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** A SWF the shell opened, by the URL the page fetches it from. */
|
|
87
|
+
export interface OpenedMovie {
|
|
88
|
+
url: string;
|
|
89
|
+
/** Its file name, for the page to show. */
|
|
90
|
+
name: string;
|
|
91
|
+
/** The sandbox it plays in, for Security.sandboxType. */
|
|
92
|
+
sandbox: SandboxType;
|
|
93
|
+
/** For an AIR application opened by its descriptor: its launch, which plays it as AIR's. */
|
|
94
|
+
air?: AirLaunch;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The libraries' paths on disk, null for one the shell has not found. */
|
|
98
|
+
/** A playerglobal.abc the user chose in place of swf2es's own; builtin.abc ships with the player. */
|
|
99
|
+
export interface LibraryState {
|
|
100
|
+
playerglobal: string | null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** What the page starts from: the libraries, and the SWF to play, if one is open. */
|
|
104
|
+
export interface StartState {
|
|
105
|
+
/** The user's opt-in; changing it restarts the page. */
|
|
106
|
+
stage3D: boolean;
|
|
107
|
+
libraries: LibraryState;
|
|
108
|
+
movie: OpenedMovie | null;
|
|
109
|
+
/** The app's build, a short commit, for the context menu's About item; null where unknown. */
|
|
110
|
+
build: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export type LibraryName = keyof LibraryState;
|
|
114
|
+
|
|
115
|
+
/** What befalls a socket, as player's SocketEvents has it. */
|
|
116
|
+
export type SocketEvent =
|
|
117
|
+
| {
|
|
118
|
+
type: "open";
|
|
119
|
+
localAddress: string;
|
|
120
|
+
localPort: number;
|
|
121
|
+
remoteAddress: string;
|
|
122
|
+
remotePort: number;
|
|
123
|
+
}
|
|
124
|
+
| { type: "data"; bytes: Uint8Array }
|
|
125
|
+
| { type: "close" }
|
|
126
|
+
| { type: "error"; message: string };
|
|
127
|
+
|
|
128
|
+
/** flash.net.Socket's TCP connections, opened by the shell. */
|
|
129
|
+
export interface DesktopSockets {
|
|
130
|
+
/** A connection's id; its events follow, an "error" one if the shell refuses it. */
|
|
131
|
+
connect(host: string, port: number): number;
|
|
132
|
+
send(id: number, bytes: Uint8Array): void;
|
|
133
|
+
close(id: number): void;
|
|
134
|
+
onEvent(listener: (id: number, event: SocketEvent) => void): void;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A request of a SWF's, as player's FetchRequest has it. */
|
|
138
|
+
export interface NetworkRequest {
|
|
139
|
+
url: string;
|
|
140
|
+
method: string;
|
|
141
|
+
headers: [string, string][];
|
|
142
|
+
body: Uint8Array | null;
|
|
143
|
+
/** "movie" for the SWF the page plays, else what the SWF loads it for. */
|
|
144
|
+
purpose: "movie" | "content" | "data" | "send";
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Its response, as player's FetchResult has it: no bytes for a failure. */
|
|
148
|
+
export interface NetworkResponse {
|
|
149
|
+
bytes: Uint8Array | null;
|
|
150
|
+
status: number;
|
|
151
|
+
headers: [string, string][];
|
|
152
|
+
url?: string;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** A SWF's http and https requests, sent and judged by the shell, as Flash's sandboxes had them. */
|
|
156
|
+
export interface DesktopNetwork {
|
|
157
|
+
/**
|
|
158
|
+
* The response, or a rejection where the shell refused the request.
|
|
159
|
+
* `cancel` is called at once with what aborts it.
|
|
160
|
+
*/
|
|
161
|
+
fetch(request: NetworkRequest, cancel: (abort: () => void) => void): Promise<NetworkResponse>;
|
|
162
|
+
/** A policy file the SWF named with Security.loadPolicyFile. */
|
|
163
|
+
loadPolicyFile(url: string): void;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface DesktopFile {
|
|
167
|
+
id: number;
|
|
168
|
+
name: string;
|
|
169
|
+
size: number;
|
|
170
|
+
modificationDate: number;
|
|
171
|
+
creationDate: number;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface DesktopFiles {
|
|
175
|
+
browse(
|
|
176
|
+
filters: { description: string; extension: string }[],
|
|
177
|
+
multiple: boolean,
|
|
178
|
+
): Promise<DesktopFile[]>;
|
|
179
|
+
save(name: string): Promise<{ id: number; name: string } | null>;
|
|
180
|
+
read(id: number): Promise<Uint8Array>;
|
|
181
|
+
write(id: number, bytes: Uint8Array): Promise<void>;
|
|
182
|
+
release(id: number): void;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export interface DesktopApi {
|
|
186
|
+
files: DesktopFiles;
|
|
187
|
+
/** The page has loaded and listens: what it is to show. */
|
|
188
|
+
start(): Promise<StartState>;
|
|
189
|
+
/** The shell opened a SWF: play it in place of what plays. */
|
|
190
|
+
onOpen(listener: (movie: OpenedMovie) => void): void;
|
|
191
|
+
/** The shell closed the SWF playing. */
|
|
192
|
+
onClose(listener: () => void): void;
|
|
193
|
+
/** Ask for the open dialog. */
|
|
194
|
+
openDialog(): void;
|
|
195
|
+
/** Ask for the dialog that opens a SWF by its URL, which only the user answers. */
|
|
196
|
+
openUrlDialog(): void;
|
|
197
|
+
/** A file dropped on the page: the shell opens it if it is a SWF. */
|
|
198
|
+
openDropped(file: File): void;
|
|
199
|
+
/** Ask the user for a library; the page reloads once the shell has it. */
|
|
200
|
+
chooseLibrary(name: LibraryName): void;
|
|
201
|
+
sockets: DesktopSockets;
|
|
202
|
+
network: DesktopNetwork;
|
|
203
|
+
air: DesktopAir;
|
|
204
|
+
}
|
package/static/icon.png
ADDED
|
Binary file
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>swf2es</title>
|
|
6
|
+
<script type="importmap">{"imports":{"@swf2es/native/compress":"/modules/native/compress/index.js","@swf2es/format":"/modules/format/index.js","@swf2es/native/mp3":"/modules/native/mp3/index.js","@swf2es/native/atf":"/modules/native/atf/index.js","@swf2es/native/audio":"/modules/native/audio/index.js","@swf2es/native/render":"/modules/native/render/index.js","@swf2es/codegen":"/modules/codegen/index.js","@swf2es/runtime":"/modules/runtime/index.js","@swf2es/player":"/modules/player/index.js","@swf2es/player-hosts/indexeddb":"/modules/player-hosts/indexeddb.js","@swf2es/player-hosts/precompiled":"/modules/player-hosts/precompiled.js","@swf2es/player-hosts/websocket":"/modules/player-hosts/websocket.js","@swf2es/player-hosts/workers":"/modules/player-hosts/workers.js","@swf2es/web":"/modules/web/index.js","@swf2es/codegen/codegen.wasm":"/modules/codegen/codegen.wasm","@swf2es/context3d":"/modules/context3d/index.js","@swf2es/context3d/webgl":"/modules/context3d/webgl/index.js","@swf2es/render":"/modules/render/index.js","@swf2es/render/webgl":"/modules/render/webgl/index.js","@swf2es/context3d/device":"/modules/context3d/device/index.js","@swf2es/player/scene":"/modules/player/scene/view.js","@swf2es/player/context3d":"/modules/player/playerglobal/context3d.js","@swf2es/player-hosts/stage3d":"/modules/player-hosts/stage3d.js"}}</script>
|
|
7
|
+
<link rel="stylesheet" href="/style.css">
|
|
8
|
+
<script type="module" src="/renderer/index.js"></script>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<swf2es-player id="player" allowscriptaccess="never" scale="showAll" hidden></swf2es-player>
|
|
12
|
+
<main id="welcome">
|
|
13
|
+
<h1>swf2es</h1>
|
|
14
|
+
<p>Open a SWF with File › Open, by its URL with File › Open URL, or drop one on this window.</p>
|
|
15
|
+
<p>
|
|
16
|
+
<button id="open" type="button">Open a SWF…</button>
|
|
17
|
+
<button id="open-url" type="button">Open a URL…</button>
|
|
18
|
+
</p>
|
|
19
|
+
</main>
|
|
20
|
+
<p id="failure" role="alert" hidden></p>
|
|
21
|
+
</body>
|
|
22
|
+
</html>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Open URL</title>
|
|
6
|
+
<link rel="stylesheet" href="/style.css">
|
|
7
|
+
<script type="module" src="/renderer/open-url.js"></script>
|
|
8
|
+
</head>
|
|
9
|
+
<body class="prompt">
|
|
10
|
+
<form id="form">
|
|
11
|
+
<label for="url">Open a SWF by its URL (http or https):</label>
|
|
12
|
+
<input id="url" type="text" inputmode="url" spellcheck="false" autocomplete="off"
|
|
13
|
+
placeholder="https://example.com/movie.swf" required>
|
|
14
|
+
<p id="problem" role="alert" hidden>Only an http or https URL opens.</p>
|
|
15
|
+
<div class="buttons">
|
|
16
|
+
<button id="cancel" type="button">Cancel</button>
|
|
17
|
+
<button type="submit">Open</button>
|
|
18
|
+
</div>
|
|
19
|
+
</form>
|
|
20
|
+
</body>
|
|
21
|
+
</html>
|
package/static/style.css
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: light dark;
|
|
3
|
+
font-family: system-ui, sans-serif;
|
|
4
|
+
--muted: #666;
|
|
5
|
+
--panel: #f3f3f3;
|
|
6
|
+
--error: #c0392b;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
@media (prefers-color-scheme: dark) {
|
|
10
|
+
:root {
|
|
11
|
+
--muted: #aaa;
|
|
12
|
+
--panel: #2a2a2a;
|
|
13
|
+
--error: #ff7b6b;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
html,
|
|
18
|
+
body {
|
|
19
|
+
height: 100%;
|
|
20
|
+
margin: 0;
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
swf2es-player {
|
|
25
|
+
display: block;
|
|
26
|
+
position: fixed;
|
|
27
|
+
inset: 0;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
[hidden] {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#welcome {
|
|
37
|
+
display: flex;
|
|
38
|
+
flex-direction: column;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
height: 100%;
|
|
42
|
+
color: var(--muted);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
#welcome[hidden] {
|
|
46
|
+
display: none;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#welcome h1 {
|
|
50
|
+
margin: 0 0 0.5em;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#failure {
|
|
55
|
+
position: fixed;
|
|
56
|
+
left: 16px;
|
|
57
|
+
right: 16px;
|
|
58
|
+
max-width: 640px;
|
|
59
|
+
margin: 0 auto;
|
|
60
|
+
padding: 12px 16px;
|
|
61
|
+
border-radius: 8px;
|
|
62
|
+
background: var(--panel);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#failure {
|
|
66
|
+
top: 16px;
|
|
67
|
+
color: var(--error);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* The URL dialog. */
|
|
71
|
+
body.prompt {
|
|
72
|
+
overflow: auto;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.prompt form {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
gap: 8px;
|
|
79
|
+
padding: 16px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.prompt input {
|
|
83
|
+
font: inherit;
|
|
84
|
+
padding: 4px 6px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.prompt #problem {
|
|
88
|
+
margin: 0;
|
|
89
|
+
color: var(--error);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.prompt .buttons {
|
|
93
|
+
display: flex;
|
|
94
|
+
justify-content: flex-end;
|
|
95
|
+
gap: 8px;
|
|
96
|
+
}
|