chemicaljs 2.6.4 → 3.0.1
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/.gitignore +23 -0
- package/AdblockPlugin.js +166 -0
- package/Chemical.svelte +248 -0
- package/Frame.svelte +102 -0
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/blacklist.txt +230974 -0
- package/index.js +115 -0
- package/package.json +28 -44
- package/pnpm-workspace.yaml +3 -0
- package/sw.js +7 -0
- package/client/chemical.cloaking.js +0 -48
- package/client/chemical.components.js +0 -214
- package/client/chemical.demo.html +0 -43
- package/client/chemical.js +0 -494
- package/client/chemical.sw.js +0 -43
- package/config/uv/uv.config.js +0 -10
- package/dist/index.cjs +0 -462
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -58
- package/dist/index.d.ts +0 -58
- package/dist/index.js +0 -435
- package/dist/index.js.map +0 -1
- package/ultraviolet/dist/_hPRTiIRrX.bundle.js +0 -7
- package/ultraviolet/dist/_hPRTiIRrX.client.js +0 -4
- package/ultraviolet/dist/_hPRTiIRrX.config.js +0 -10
- package/ultraviolet/dist/_hPRTiIRrX.handler.js +0 -1
- package/ultraviolet/dist/_hPRTiIRrX.sw.js +0 -47
- package/ultraviolet/index.js +0 -8
- package/ultraviolet/path.js +0 -3
package/index.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { bootstrap } from "@mercuryworkshop/proxy-bootstrap";
|
|
2
|
+
import express from "express";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const swPath = fileURLToPath(new URL("./sw.js", import.meta.url));
|
|
9
|
+
|
|
10
|
+
export class Chemical {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
this.port = options.port || 8000;
|
|
13
|
+
this.staticDir = options.staticDir || "build";
|
|
14
|
+
this.spaMode = options.spaMode || false;
|
|
15
|
+
|
|
16
|
+
this.app = express();
|
|
17
|
+
this.server = http.createServer(this.app);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async start() {
|
|
21
|
+
const { routeRequest, routeUpgrade } = await bootstrap({
|
|
22
|
+
scramjetBundlePath: "/scramjet/scramjet.js",
|
|
23
|
+
scramjetWasmPath: "/scramjet/scramjet.wasm",
|
|
24
|
+
scramjetUtilsBundlePath: "/scramjet/scramjet-utils.js",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
this.app.use((req, res, next) => {
|
|
28
|
+
if (routeRequest(req, res)) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
next();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.app.get("/sw.js", (req, res) => {
|
|
35
|
+
res.sendFile(swPath);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
this.app.use(express.static(this.staticDir));
|
|
39
|
+
|
|
40
|
+
if (this.spaMode) {
|
|
41
|
+
this.app.get("*", (req, res) => {
|
|
42
|
+
res.sendFile(path.resolve(process.cwd(), this.staticDir, "index.html"));
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this.server.on("upgrade", (req, socket, head) => {
|
|
47
|
+
routeUpgrade(req, socket, head);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
this.server.listen(this.port, () => {
|
|
52
|
+
console.log(`Running on http://localhost:${this.port}`);
|
|
53
|
+
resolve(this.server);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
stop() {
|
|
59
|
+
if (this.server) {
|
|
60
|
+
this.server.close();
|
|
61
|
+
console.log("Server stopped");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const ChemicalVitePlugin = () => ({
|
|
67
|
+
name: "chemical-vite-plugin",
|
|
68
|
+
config() {
|
|
69
|
+
return {
|
|
70
|
+
optimizeDeps: {
|
|
71
|
+
include: [
|
|
72
|
+
"@mercuryworkshop/scramjet",
|
|
73
|
+
"@mercuryworkshop/scramjet-controller",
|
|
74
|
+
"@mercuryworkshop/proxy-bootstrap",
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
},
|
|
79
|
+
async configureServer(server) {
|
|
80
|
+
const { routeRequest, routeUpgrade } = await bootstrap({
|
|
81
|
+
scramjetBundlePath: "/scramjet/scramjet.js",
|
|
82
|
+
scramjetWasmPath: "/scramjet/scramjet.wasm",
|
|
83
|
+
scramjetUtilsBundlePath: "/scramjet/scramjet-utils.js",
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
server.middlewares.use((req, res, next) => {
|
|
87
|
+
const urlPath = req.url.split("?")[0];
|
|
88
|
+
|
|
89
|
+
if (urlPath === "/sw.js") {
|
|
90
|
+
fs.readFile(swPath, (err, data) => {
|
|
91
|
+
if (err) {
|
|
92
|
+
res.statusCode = 404;
|
|
93
|
+
res.end("Service Worker not found");
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
97
|
+
res.end(data);
|
|
98
|
+
});
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (routeRequest(req, res)) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
next();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (server.httpServer) {
|
|
110
|
+
server.httpServer.on("upgrade", (req, socket, head) => {
|
|
111
|
+
routeUpgrade(req, socket, head);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
});
|
package/package.json
CHANGED
|
@@ -1,56 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chemicaljs",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.1",
|
|
4
4
|
"description": "Easily create your own web proxy with no experience required.",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
"import": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"default": "./dist/index.js"
|
|
13
|
-
},
|
|
14
|
-
"require": {
|
|
15
|
-
"types": "./dist/index.d.cts",
|
|
16
|
-
"default": "./dist/index.cjs"
|
|
17
|
-
}
|
|
18
|
-
},
|
|
19
|
-
"files": [
|
|
20
|
-
"dist",
|
|
21
|
-
"client",
|
|
22
|
-
"config",
|
|
23
|
-
"ultraviolet"
|
|
24
|
-
],
|
|
5
|
+
"author": "Nebelung",
|
|
6
|
+
"license": "AGPL-3.0-only",
|
|
25
7
|
"repository": {
|
|
26
8
|
"type": "git",
|
|
27
9
|
"url": "git+https://github.com/chemicaljs/chemical.git"
|
|
28
10
|
},
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "index.js",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./index.js",
|
|
15
|
+
"./Chemical": "./Chemical.svelte",
|
|
16
|
+
"./Frame": "./Frame.svelte"
|
|
17
|
+
},
|
|
18
|
+
"devEngines": {
|
|
19
|
+
"packageManager": {
|
|
20
|
+
"name": "pnpm",
|
|
21
|
+
"version": "12.8.1",
|
|
22
|
+
"onFail": "download"
|
|
23
|
+
}
|
|
35
24
|
},
|
|
36
25
|
"dependencies": {
|
|
37
|
-
"@mercuryworkshop/
|
|
38
|
-
"@mercuryworkshop/
|
|
39
|
-
"@mercuryworkshop/
|
|
40
|
-
"@mercuryworkshop/scramjet": "
|
|
41
|
-
"@mercuryworkshop/
|
|
42
|
-
"@
|
|
43
|
-
"express": "^
|
|
44
|
-
"glob": "^11.0.0",
|
|
45
|
-
"nanoid": "^5.0.9",
|
|
46
|
-
"rammerhead": "https://github.com/chemicaljs/chemical/raw/main/rammerhead.tgz",
|
|
47
|
-
"typescript": "^5.7.2",
|
|
48
|
-
"vite": "^6.0.6"
|
|
26
|
+
"@mercuryworkshop/epoxy-transport": "^3.0.1",
|
|
27
|
+
"@mercuryworkshop/libcurl-transport": "^2.0.5",
|
|
28
|
+
"@mercuryworkshop/proxy-bootstrap": "^0.0.5",
|
|
29
|
+
"@mercuryworkshop/scramjet": "^1.1.0",
|
|
30
|
+
"@mercuryworkshop/scramjet-controller": "^0.0.14",
|
|
31
|
+
"@mercuryworkshop/scramjet-utils": "^0.0.3",
|
|
32
|
+
"express": "^5.2.1"
|
|
49
33
|
},
|
|
50
|
-
"
|
|
51
|
-
"
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"svelte": "^5.56.1"
|
|
52
36
|
},
|
|
53
|
-
"
|
|
54
|
-
"
|
|
37
|
+
"scripts": {
|
|
38
|
+
"fetch-adblock": "curl -o blacklist.txt https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro.txt"
|
|
55
39
|
}
|
|
56
|
-
}
|
|
40
|
+
}
|
package/sw.js
ADDED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
class ChemicalTitle extends HTMLTitleElement {
|
|
2
|
-
constructor() {
|
|
3
|
-
super();
|
|
4
|
-
}
|
|
5
|
-
connectedCallback() {
|
|
6
|
-
setTimeout(() => {
|
|
7
|
-
this.setAttribute("data-title", this.innerText);
|
|
8
|
-
|
|
9
|
-
const title =
|
|
10
|
-
this.dataset.titleStore !== undefined
|
|
11
|
-
? localStorage.getItem("@chemical/title") ||
|
|
12
|
-
this.getAttribute("data-title")
|
|
13
|
-
: this.getAttribute("data-title");
|
|
14
|
-
|
|
15
|
-
this.innerText = title;
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
class ChemicalIcon extends HTMLLinkElement {
|
|
21
|
-
constructor() {
|
|
22
|
-
super();
|
|
23
|
-
}
|
|
24
|
-
connectedCallback() {
|
|
25
|
-
setTimeout(() => {
|
|
26
|
-
this.setAttribute("data-icon", this.getAttribute("href"));
|
|
27
|
-
|
|
28
|
-
const icon =
|
|
29
|
-
this.dataset.iconStore !== undefined
|
|
30
|
-
? localStorage.getItem("@chemical/icon") ||
|
|
31
|
-
this.getAttribute("data-icon")
|
|
32
|
-
: this.getAttribute("data-icon");
|
|
33
|
-
|
|
34
|
-
this.setAttribute("href", icon);
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
customElements.define("chemical-title", ChemicalTitle, { extends: "title" });
|
|
40
|
-
customElements.define("chemical-icon", ChemicalIcon, { extends: "link" });
|
|
41
|
-
|
|
42
|
-
window.chemical.aboutBlank = function (url) {
|
|
43
|
-
var page = window.open();
|
|
44
|
-
page.document.body.innerHTML =
|
|
45
|
-
`<iframe style="height:100%; width: 100%; border: none; position: fixed; top: 0; right: 0; left: 0; bottom: 0; border: none" sandbox="allow-forms allow-modals allow-orientation-lock allow-pointer-lock allow-popups allow-popups-to-escape-sandbox allow-presentation allow-same-origin allow-scripts allow-top-navigation allow-top-navigation-by-user-activation" src="` +
|
|
46
|
-
url +
|
|
47
|
-
`"></iframe>`;
|
|
48
|
-
};
|
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
class ChemicalInput extends HTMLInputElement {
|
|
2
|
-
constructor() {
|
|
3
|
-
super();
|
|
4
|
-
}
|
|
5
|
-
connectedCallback() {
|
|
6
|
-
this.addEventListener("keydown", async function (e) {
|
|
7
|
-
if (e.key === "Enter" && window.chemical.loaded && e.target.value) {
|
|
8
|
-
let service =
|
|
9
|
-
this.dataset.serviceStore !== undefined
|
|
10
|
-
? localStorage.getItem("@chemical/service") ||
|
|
11
|
-
this.dataset.service ||
|
|
12
|
-
"uv"
|
|
13
|
-
: this.dataset.service || "uv";
|
|
14
|
-
let autoHttps =
|
|
15
|
-
this.dataset.autoHttpsStore !== undefined
|
|
16
|
-
? localStorage.getItem("@chemical/autoHttps") === "true"
|
|
17
|
-
: this.dataset.autoHttps !== undefined
|
|
18
|
-
? true
|
|
19
|
-
: false;
|
|
20
|
-
let searchEngine =
|
|
21
|
-
this.dataset.searchEngineStore !== undefined
|
|
22
|
-
? localStorage.getItem("@chemical/searchEngine") || this.dataset.searchEngine
|
|
23
|
-
: this.dataset.searchEngine;
|
|
24
|
-
let action = this.dataset.action;
|
|
25
|
-
let target = this.dataset.target;
|
|
26
|
-
let frame = this.dataset.frame;
|
|
27
|
-
let encodedURL = await chemical.encode(e.target.value, {
|
|
28
|
-
service,
|
|
29
|
-
autoHttps,
|
|
30
|
-
searchEngine,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
if (frame) {
|
|
34
|
-
let forFrame = document.getElementById(frame);
|
|
35
|
-
forFrame.src = encodedURL;
|
|
36
|
-
forFrame.setAttribute("data-open", "true");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (action) {
|
|
40
|
-
window[action](encodedURL);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (target) {
|
|
44
|
-
if (target === "_self") {
|
|
45
|
-
window.location = encodedURL;
|
|
46
|
-
} else if (target === "_blank") {
|
|
47
|
-
window.open(encodedURL);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
class ChemicalButton extends HTMLButtonElement {
|
|
56
|
-
constructor() {
|
|
57
|
-
super();
|
|
58
|
-
}
|
|
59
|
-
connectedCallback() {
|
|
60
|
-
this.addEventListener("click", function (e) {
|
|
61
|
-
let forInput = document.getElementById(this.dataset.for);
|
|
62
|
-
|
|
63
|
-
if (forInput) {
|
|
64
|
-
forInput.dispatchEvent(
|
|
65
|
-
new KeyboardEvent("keydown", {
|
|
66
|
-
key: "Enter",
|
|
67
|
-
})
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
class ChemicalIFrame extends HTMLIFrameElement {
|
|
75
|
-
static observedAttributes = ["data-open"];
|
|
76
|
-
constructor() {
|
|
77
|
-
super();
|
|
78
|
-
}
|
|
79
|
-
connectedCallback() {
|
|
80
|
-
let open = this.dataset.open;
|
|
81
|
-
this.style.display = open === "true" ? "" : "none";
|
|
82
|
-
}
|
|
83
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
84
|
-
if (name === "data-open") {
|
|
85
|
-
let open = this.dataset.open;
|
|
86
|
-
this.style.display = open === "true" ? "" : "none";
|
|
87
|
-
|
|
88
|
-
let controls = document.getElementById(this.dataset.controls);
|
|
89
|
-
|
|
90
|
-
if (controls) {
|
|
91
|
-
controls.dataset.open = open;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
class ChemicalControls extends HTMLElement {
|
|
98
|
-
static observedAttributes = ["data-open"];
|
|
99
|
-
constructor() {
|
|
100
|
-
super();
|
|
101
|
-
}
|
|
102
|
-
connectedCallback() {
|
|
103
|
-
let open = this.dataset.open;
|
|
104
|
-
this.style.display = open === "true" ? "" : "none";
|
|
105
|
-
}
|
|
106
|
-
attributeChangedCallback(name, oldValue, newValue) {
|
|
107
|
-
if (name === "data-open") {
|
|
108
|
-
let open = this.dataset.open;
|
|
109
|
-
this.style.display = open === "true" ? "" : "none";
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
class ChemicalLink extends HTMLAnchorElement {
|
|
115
|
-
constructor() {
|
|
116
|
-
super();
|
|
117
|
-
}
|
|
118
|
-
async connectedCallback() {
|
|
119
|
-
let href = this.dataset.href;
|
|
120
|
-
let service = this.dataset.service || "uv";
|
|
121
|
-
let autoHttps = this.dataset.autoHttps !== undefined ? true : false;
|
|
122
|
-
let searchEngine = this.dataset.searchEngine;
|
|
123
|
-
this.dataset.chemicalLoading = "true";
|
|
124
|
-
|
|
125
|
-
if (window.chemical.loaded) {
|
|
126
|
-
this.setAttribute(
|
|
127
|
-
"href",
|
|
128
|
-
await chemical.encode(href, {
|
|
129
|
-
service,
|
|
130
|
-
autoHttps,
|
|
131
|
-
searchEngine,
|
|
132
|
-
})
|
|
133
|
-
);
|
|
134
|
-
this.dataset.chemicalLoading = "false";
|
|
135
|
-
} else {
|
|
136
|
-
window.addEventListener("chemicalLoaded", async () => {
|
|
137
|
-
this.setAttribute(
|
|
138
|
-
"href",
|
|
139
|
-
await chemical.encode(href, {
|
|
140
|
-
service,
|
|
141
|
-
autoHttps,
|
|
142
|
-
searchEngine,
|
|
143
|
-
})
|
|
144
|
-
);
|
|
145
|
-
this.dataset.chemicalLoading = "false";
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
class ChemicalSelect extends HTMLSelectElement {
|
|
152
|
-
constructor() {
|
|
153
|
-
super();
|
|
154
|
-
}
|
|
155
|
-
connectedCallback() {
|
|
156
|
-
const store = this.dataset.defaultStore;
|
|
157
|
-
|
|
158
|
-
this.addEventListener("change", function () {
|
|
159
|
-
window.chemical.setStore(store, this.value);
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
if (store) {
|
|
163
|
-
const value = window.chemical.getStore(store);
|
|
164
|
-
|
|
165
|
-
const observerOptions = {
|
|
166
|
-
childList: true,
|
|
167
|
-
subtree: false,
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const observer = new MutationObserver((records, observer) => {
|
|
171
|
-
for (const record of records) {
|
|
172
|
-
for (const addedNode of record.addedNodes) {
|
|
173
|
-
if (addedNode.tagName === "OPTION") {
|
|
174
|
-
if (addedNode.getAttribute("value") === value) {
|
|
175
|
-
addedNode.setAttribute("selected", "");
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
observer.observe(this, observerOptions);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
customElements.define("chemical-input", ChemicalInput, { extends: "input" });
|
|
187
|
-
customElements.define("chemical-button", ChemicalButton, { extends: "button" });
|
|
188
|
-
customElements.define("chemical-iframe", ChemicalIFrame, { extends: "iframe" });
|
|
189
|
-
customElements.define("chemical-controls", ChemicalControls, {
|
|
190
|
-
extends: "section",
|
|
191
|
-
});
|
|
192
|
-
customElements.define("chemical-link", ChemicalLink, { extends: "a" });
|
|
193
|
-
customElements.define("chemical-select", ChemicalSelect, { extends: "select" });
|
|
194
|
-
|
|
195
|
-
window.chemical.componentAction = function (action, frameID) {
|
|
196
|
-
let frame = document.getElementById(frameID);
|
|
197
|
-
|
|
198
|
-
if (frame) {
|
|
199
|
-
switch (action) {
|
|
200
|
-
case "back":
|
|
201
|
-
frame.contentWindow.history.back();
|
|
202
|
-
break;
|
|
203
|
-
case "forward":
|
|
204
|
-
frame.contentWindow.history.forward();
|
|
205
|
-
break;
|
|
206
|
-
case "reload":
|
|
207
|
-
frame.contentWindow.location.reload();
|
|
208
|
-
break;
|
|
209
|
-
case "close":
|
|
210
|
-
frame.dataset.open = "false";
|
|
211
|
-
frame.src = "";
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8" />
|
|
5
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
-
<title>Demo Site</title>
|
|
7
|
-
<style>
|
|
8
|
-
*,
|
|
9
|
-
*::before,
|
|
10
|
-
*::after {
|
|
11
|
-
box-sizing: border-box;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
body {
|
|
15
|
-
margin: 0;
|
|
16
|
-
min-height: 100vh;
|
|
17
|
-
display: flex;
|
|
18
|
-
flex-direction: column;
|
|
19
|
-
justify-content: center;
|
|
20
|
-
align-items: center;
|
|
21
|
-
font-family: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
|
|
22
|
-
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
|
23
|
-
background: #e5e5e5;
|
|
24
|
-
color: black;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@media (prefers-color-scheme: dark) {
|
|
28
|
-
body {
|
|
29
|
-
background: #0a0a0a;
|
|
30
|
-
color: #fafafa;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
h1 {
|
|
35
|
-
margin: 0;
|
|
36
|
-
}
|
|
37
|
-
</style>
|
|
38
|
-
</head>
|
|
39
|
-
<body>
|
|
40
|
-
<h1>Demo Site</h1>
|
|
41
|
-
<p>This is a demo site without proxy functionality.</p>
|
|
42
|
-
</body>
|
|
43
|
-
</html>
|