Skip to content

Commit 696576d

Browse files
committed
Pkgs + test CSP + cookies -> localStorage
1 parent 8d7f754 commit 696576d

12 files changed

+248
-226
lines changed

.github/workflows/eslint.yml

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
name: ESLint
22

33
on:
4+
pull_request:
45
push:
56

67
jobs:
@@ -15,6 +16,7 @@ jobs:
1516
uses: actions/setup-node@v4
1617
with:
1718
node-version: 21
19+
cache: "npm"
1820

1921
- name: "🛸 install eslint html plugins"
2022
run: npm i --omit=optional

_headers

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
Content-Security-Policy-Report-Only: default-src 'none' 'report-sample'; script-src-elem 'self'; script-src-attr 'unsafe-inline'; style-src-elem 'self'; style-src-attr 'unsafe-inline'; img-src 'self'; connect-src 'self' https://sh0rt.zip/ https://cloudflareinsights.com/cdn-cgi/rum https://static.cloudflareinsights.com; form-action 'none'; frame-ancestors 'none'; worker-src 'self'; manifest-src 'self'; report-uri https://api.tomatenkuchen.com/csp-violation
3+
Report-To: {"group":"default","max_age":2592000,"endpoints":[{"url":"https://api.tomatenkuchen.com/csp-violation"}],"include_subdomains":false}
4+
Cross-Origin-Opener-Policy: same-origin
5+
X-Frame-Options: DENY
6+
X-Content-Type-Options: nosniff
7+
Referrer-Policy: strict-origin-when-cross-origin

manifest.json assets/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"scope": "/",
5252
"theme_color": "#216E4A",
5353
"lang": "en",
54-
"description": "A tool which allows you to analyze Minecraft Java data and resource packs, and generate stats and share from them.",
54+
"description": "A tool which allows you to analyze Minecraft Java data and resource packs, and generate shareable stats from them.",
5555
"screenshots": [
5656
{
5757
"src": "/assets/images/showcase1.png",

assets/script.js

+51-59
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,12 @@
1-
// Cookie/"load" code modified from https://github.com/DEVTomatoCake/dashboard/blob/700b21999a671f4e9c32ba4a1a35f94156db11d4/assets/js/script.js#L16-L31
2-
3-
function setCookie(name = "", value = "", days = void 0) {
4-
let cookie = name + "=" + value + ";path=/;Secure;"
5-
if (days) cookie += "expires=" + new Date(Date.now() + 1000 * 60 * 60 * 24 * days).toUTCString() + ";"
6-
7-
document.cookie = cookie
8-
}
9-
function getCookie(name) {
10-
for (const rawCookie of document.cookie.split(";")) {
11-
const cookie = rawCookie.trim()
12-
if (cookie.split("=")[0] == name) return cookie.substring(name.length + 1, cookie.length)
13-
}
14-
return void 0
15-
}
1+
// "load" code modified from https://github.com/DEVTomatoCake/dashboard/blob/700b21999a671f4e9c32ba4a1a35f94156db11d4/assets/js/script.js#L16-L31
162

173
const requestVersions = async () => {
18-
const res = await fetch("https://raw.githubusercontent.com/misode/mcmeta/summary/versions/data.json")
4+
const res = await fetch("https://raw.githubusercontent.com/misode/mcmeta/summary/versions/data.json", {
5+
headers: {
6+
Accept: "application/json",
7+
"User-Agent": "DEVTomatoCake/Pack-Analyzer"
8+
}
9+
})
1910
const json = await res.json()
2011
window.versions = json.map(ver => ({
2112
name: ver.id,
@@ -91,11 +82,11 @@ let rpExclusive = {
9182
textures: 0
9283
}
9384

94-
window.addEventListener("load", () => {
95-
if (getCookie("theme") == "light") document.body.classList.add("light")
85+
window.addEventListener("DOMContentLoaded", () => {
86+
if (localStorage.getItem("theme") == "light") document.body.classList.add("light")
9687
else if (window.matchMedia("(prefers-color-scheme: light)").matches) {
9788
document.body.classList.add("light")
98-
setCookie("theme", "light", 365)
89+
localStorage.setItem("theme", "light")
9990
}
10091

10192
const params = new URLSearchParams(location.search)
@@ -122,6 +113,46 @@ window.addEventListener("load", () => {
122113
mainScan(true)
123114
}
124115

116+
document.getElementById("clear-results").addEventListener("click", () => {
117+
document.getElementById("progress").innerText = ""
118+
document.getElementById("result").innerHTML = ""
119+
document.getElementById("resultButtons").hidden = true
120+
document.getElementById("shareImage").style.display = "none"
121+
if (interval) clearInterval(interval)
122+
})
123+
document.getElementById("toggle-theme").addEventListener("click", () => {
124+
localStorage.setItem("theme", document.body.classList.toggle("light") ? "light" : "dark")
125+
})
126+
document.getElementById("about-button").addEventListener("click", () => openDialog(document.getElementById("aboutDialog")))
127+
128+
document.getElementById("select-folder").addEventListener("click", () => {
129+
if (interval) clearInterval(interval)
130+
selected = null
131+
132+
const input = document.createElement("input")
133+
input.type = "file"
134+
input.webkitdirectory = true
135+
input.onchange = e => {
136+
selected = e.target.files
137+
mainScan()
138+
}
139+
if ("showPicker" in HTMLInputElement.prototype) input.showPicker()
140+
else input.click()
141+
})
142+
document.getElementById("select-zip").addEventListener("click", () => {
143+
if (interval) clearInterval(interval)
144+
145+
const input = document.createElement("input")
146+
input.type = "file"
147+
input.accept = ".zip"
148+
input.onchange = e => handleZip(e.target.files[0])
149+
150+
if ("showPicker" in HTMLInputElement.prototype) input.showPicker()
151+
else input.click()
152+
})
153+
154+
for (const elem of document.getElementsByClassName("share")) elem.addEventListener("click", () => share(elem.dataset.type))
155+
125156
if (location.protocol == "https:" && "serviceWorker" in navigator) navigator.serviceWorker.register("/serviceworker.js")
126157
})
127158

@@ -182,18 +213,6 @@ function openDialog(dialog) {
182213
}
183214
}
184215

185-
const toggleTheme = () => {
186-
setCookie("theme", document.body.classList.toggle("light") ? "light" : "dark", 365)
187-
}
188-
189-
const clearResults = () => {
190-
document.getElementById("progress").innerText = ""
191-
document.getElementById("result").innerHTML = ""
192-
document.getElementById("resultButtons").hidden = true
193-
document.getElementById("shareImage").style.display = "none"
194-
if (interval) clearInterval(interval)
195-
}
196-
197216
async function share(type) {
198217
let content = ""
199218
if (type == "txt") content = document.getElementById("result").innerText
@@ -239,7 +258,7 @@ async function share(type) {
239258
if (res.ok) {
240259
document.getElementById("share-link").href = "https://sh0rt.zip/" + name
241260
document.getElementById("share-link").innerText = "https://sh0rt.zip/" + name
242-
document.getElementById("share-img").src = "https://api.qrserver.com/v1/create-qr-code/?data=" + encodeURIComponent("https://sh0rt.zip/" + name) + "&size=150x150&qzone=2"
261+
document.getElementById("share-img").src = "https://sh0rt.zip/qr/" + name
243262
openDialog(document.getElementById("shareDialog"))
244263
} else alert("Couldn't create link: " + json.error)
245264
return
@@ -713,33 +732,6 @@ async function mainScan(hasData = false) {
713732
}, 100)
714733
}
715734

716-
async function selectFolder() {
717-
if (interval) clearInterval(interval)
718-
selected = null
719-
720-
const input = document.createElement("input")
721-
input.type = "file"
722-
input.webkitdirectory = true
723-
input.onchange = e => {
724-
selected = e.target.files
725-
mainScan()
726-
}
727-
if ("showPicker" in HTMLInputElement.prototype) input.showPicker()
728-
else input.click()
729-
}
730-
731-
async function selectZip() {
732-
if (interval) clearInterval(interval)
733-
734-
const input = document.createElement("input")
735-
input.type = "file"
736-
input.accept = ".zip"
737-
input.onchange = e => handleZip(e.target.files[0])
738-
739-
if ("showPicker" in HTMLInputElement.prototype) input.showPicker()
740-
else input.click()
741-
}
742-
743735
function handleZip(file) {
744736
selected = []
745737

assets/style.css

+2-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ button {
4040
border: none;
4141
border-radius: 7px;
4242
cursor: pointer;
43-
box-shadow: inset 0px -1px 2px rgba(17, 24, 39, .15), 0 0 0 0 transparent;
43+
box-shadow: inset 0 -1px 2px rgba(17, 24, 39, .15), 0 0 0 0 transparent;
4444
}
4545

4646
p {
@@ -91,11 +91,9 @@ a {
9191
.indented {
9292
margin-left: 25px;
9393
}
94-
9594
.indented2 {
9695
margin-left: 50px;
9796
}
98-
9997
.indented3 {
10098
margin-left: 75px;
10199
}
@@ -134,7 +132,7 @@ summary {
134132
height: 100%;
135133
overflow: auto;
136134
background-color: var(--dialog-shadow);
137-
transition: .3;
135+
transition: .3s;
138136
}
139137

140138
.dialog-content {

eslint.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ const rules = {
103103
"prefer-const": 2,
104104
"use-isnan": 2,
105105
"valid-typeof": 2,
106+
yoda: 2,
106107

107108
"@stylistic/js/array-bracket-spacing": 2,
108109
"@stylistic/js/arrow-parens": [2, "as-needed"],
@@ -195,6 +196,8 @@ const rules = {
195196
"unicorn/require-number-to-fixed-digits-argument": 2,
196197
"unicorn/switch-case-braces": [2, "avoid"],
197198
"unicorn/text-encoding-identifier-case": 2,
199+
"unicorn/no-await-in-promise-methods": 2,
200+
"unicorn/no-single-promise-in-promise-methods": 2,
198201

199202
"sonarjs/no-extra-arguments": 2,
200203
"sonarjs/no-empty-collection": 2,

index.html

+10-10
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<meta property="og:url" content="https://pack-analyzer.pages.dev/">
1111
<meta property="og:image" content="https://pack-analyzer.pages.dev/assets/images/showcase1.png">
1212

13-
<link rel="manifest" href="./manifest.json">
13+
<link rel="manifest" href="./assets/manifest.json">
1414
<link href="./assets/images/icon-128x128.png" rel="shortcut icon" type="image/x-icon">
1515
<link href="./assets/images/icon-192x192.png" rel="apple-touch-icon" sizes="192x192">
1616

@@ -23,17 +23,17 @@
2323
<h1>Minecraft Java Data and Resource pack analyzer</h1>
2424
<h2>Drop/paste a .zip or .mcfunction file, or select a folder below to analyze it!</h2>
2525
<div>
26-
<button type="button" onclick="selectFolder()">Select folder</button>
27-
<button type="button" onclick="selectZip()">Select .zip</button>
28-
<button type="button" onclick="toggleTheme()">Toggle theme</button>
29-
<button type="button" onclick="openDialog(document.getElementById('aboutDialog'))">About</button>
26+
<button type="button" id="select-folder">Select folder</button>
27+
<button type="button" id="select-zip">Select .zip</button>
28+
<button type="button" id="toggle-theme">Toggle theme</button>
29+
<button type="button" id="about-button">About</button>
3030
</div>
3131
<div id="resultButtons" hidden>
32-
<button type="button" onclick="clearResults()">Clear results</button>
33-
<button type="button" onclick="share('txt')">Export as .txt</button>
34-
<button type="button" onclick="share('json')">Export as .json</button>
35-
<button type="button" onclick="share('link')">Share as link</button>
36-
<button type="button" onclick="share('png')">Generate image</button>
32+
<button type="button" id="clear-results">Clear results</button>
33+
<button type="button" class="share" data-type="txt">Export as .txt</button>
34+
<button type="button" class="share" data-type="json">Export as .json</button>
35+
<button type="button" class="share" data-type="link">Share as link</button>
36+
<button type="button" class="share" data-type="png">Generate image</button>
3737
</div>
3838

3939
<br>

0 commit comments

Comments
 (0)