Compare commits
4 commits
a6ec5b9e55
...
5802a00e8e
| Author | SHA1 | Date | |
|---|---|---|---|
| 5802a00e8e | |||
| 5f898194f5 | |||
| 6b586f6e07 | |||
| eb807a63a6 |
14 changed files with 196 additions and 195 deletions
|
|
@ -7,4 +7,5 @@ backend/package-lock.json
|
|||
|
||||
# Vendored / generated assets
|
||||
frontend/js/jquery.min.js
|
||||
frontend/js/plausible.js
|
||||
*.min.js
|
||||
|
|
|
|||
7
backend/package-lock.json
generated
7
backend/package-lock.json
generated
|
|
@ -8,6 +8,7 @@
|
|||
"name": "fizika-admin-backend",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@plausible-analytics/tracker": "^0.4.5",
|
||||
"cors": "^2.8.6",
|
||||
"express": "^5.2.1",
|
||||
"helmet": "^8.2.0",
|
||||
|
|
@ -20,6 +21,12 @@
|
|||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@plausible-analytics/tracker": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@plausible-analytics/tracker/-/tracker-0.4.5.tgz",
|
||||
"integrity": "sha512-6BfAGejXY+YA3Cw6LYT2Zpn4hTxDtPQAawFsYUsQCOg78wIS5C4deAGXTfJffa5VleMWITv5lpJ/EYuQBl1tPA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
"test": "node --test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@plausible-analytics/tracker": "^0.4.5",
|
||||
"express": "^5.2.1",
|
||||
"multer": "^2.1.1",
|
||||
"cors": "^2.8.6",
|
||||
|
|
|
|||
|
|
@ -1,11 +1,5 @@
|
|||
const API_BASE = window.location.origin;
|
||||
|
||||
window.plausible =
|
||||
window.plausible ||
|
||||
function () {
|
||||
(window.plausible.q = window.plausible.q || []).push(arguments);
|
||||
};
|
||||
|
||||
// Escape user-supplied text before interpolating it into HTML, to prevent XSS.
|
||||
function escapeHtml(value) {
|
||||
return String(value).replace(
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@
|
|||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Fizika Admin - Kérdések és képek kezelése</title>
|
||||
<script
|
||||
defer
|
||||
data-domain="fizika.schmelczer.dev"
|
||||
data-api="https://stats.schmelczer.dev/status"
|
||||
src="https://stats.schmelczer.dev/js/script.file-downloads.hash.outbound-links.js"
|
||||
></script>
|
||||
<script type="module" src="stats.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
|
|
|
|||
12
backend/public/stats.js
Normal file
12
backend/public/stats.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { init } from "/vendor/plausible.js";
|
||||
|
||||
// Plausible analytics via the official npm tracker (@plausible-analytics/tracker).
|
||||
// server.js serves /vendor/plausible.js straight from node_modules.
|
||||
init({
|
||||
domain: "fizika.schmelczer.dev",
|
||||
endpoint: "https://stats.schmelczer.dev/status",
|
||||
autoCapturePageviews: true,
|
||||
outboundLinks: true,
|
||||
fileDownloads: true,
|
||||
hashBasedRouting: true,
|
||||
});
|
||||
|
|
@ -37,6 +37,14 @@ app.use(
|
|||
app.use(express.json({ limit: "100mb" }));
|
||||
app.use(express.static("public"));
|
||||
|
||||
// Serve the official Plausible tracker (npm: @plausible-analytics/tracker) from node_modules.
|
||||
const plausibleTrackerPath =
|
||||
require.resolve("@plausible-analytics/tracker/plausible.js");
|
||||
|
||||
app.get("/vendor/plausible.js", (req, res) => {
|
||||
res.sendFile(plausibleTrackerPath);
|
||||
});
|
||||
|
||||
// File paths
|
||||
const DATA_PATH =
|
||||
process.env.DATA_PATH || path.join(__dirname, "../frontend/fizika.json");
|
||||
|
|
|
|||
|
|
@ -56,19 +56,7 @@
|
|||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/load.js"></script>
|
||||
<script src="js/fizika.js"></script>
|
||||
<script
|
||||
defer
|
||||
data-domain="fizika.schmelczer.dev"
|
||||
data-api="https://stats.schmelczer.dev/status"
|
||||
src="https://stats.schmelczer.dev/js/script.file-downloads.hash.outbound-links.js"
|
||||
></script>
|
||||
<script>
|
||||
window.plausible =
|
||||
window.plausible ||
|
||||
function () {
|
||||
(window.plausible.q = window.plausible.q || []).push(arguments);
|
||||
};
|
||||
</script>
|
||||
<script type="module" src="js/stat.js"></script>
|
||||
</head>
|
||||
<body onresize="aspect()">
|
||||
<div id="titlebox">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
var isSearch = false;
|
||||
var totalPoints = 0;
|
||||
var currentPoints = 0;
|
||||
var correctAnswersGiven = 0;
|
||||
var loadedQuestions = [];
|
||||
var timer = 0;
|
||||
var startTimer = 0;
|
||||
var reviewMode = 0;
|
||||
|
|
@ -17,7 +16,7 @@ function aspect() {
|
|||
async function ajaxLoad(type) {
|
||||
reviewMode = 0;
|
||||
totalPoints = 0;
|
||||
currentPoints = 0;
|
||||
loadedQuestions = [];
|
||||
$("#state").html("");
|
||||
$("#state2").html("");
|
||||
$("#percentage").html("");
|
||||
|
|
@ -92,6 +91,8 @@ async function ajaxLoad(type) {
|
|||
) {
|
||||
$("#megoldas").show();
|
||||
$("#state").html("Feladatok sikeresen letöltve!");
|
||||
startTimer = 1;
|
||||
timer = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
$("#loadingGif").hide();
|
||||
|
|
@ -116,66 +117,73 @@ async function ajaxLoad(type) {
|
|||
}
|
||||
}
|
||||
|
||||
function showCorrect(id, correctAns) {
|
||||
teszt(id, correctAns);
|
||||
eval(
|
||||
"$('" +
|
||||
"#label" +
|
||||
id +
|
||||
".rad" +
|
||||
correctAns +
|
||||
"').css('background-color', '#C6FF8C');",
|
||||
// Colour a single question green/red depending on whether the user selected
|
||||
// its correct answer, and report whether they got it right.
|
||||
function gradeQuestion(question) {
|
||||
var div = "#feladat" + question.id;
|
||||
var selected = "#form" + question.id + " #rad" + question.correct;
|
||||
var isCorrect = $(selected).is(":checked");
|
||||
$(div).animate({ backgroundColor: isCorrect ? "#C6FF8C" : "#FF808C" }, 1100);
|
||||
return isCorrect;
|
||||
}
|
||||
|
||||
// Grade every question currently on screen and return the score as a string
|
||||
// percentage (e.g. "66.67"). Grading the whole known set in one pass replaces
|
||||
// the old per-question click handlers, which accumulated across loads and
|
||||
// could save bogus results.
|
||||
function scoreLoadedQuestions() {
|
||||
var correctAnswersGiven = 0;
|
||||
loadedQuestions.forEach(function (question) {
|
||||
if (gradeQuestion(question)) correctAnswersGiven++;
|
||||
});
|
||||
var percentage = (correctAnswersGiven / totalPoints) * 100;
|
||||
percentage = Math.round(percentage * 100) / 100;
|
||||
return percentage.toFixed(2);
|
||||
}
|
||||
|
||||
// "Kiértékelés": grade the answers and, unless we are already reviewing, save
|
||||
// the result once.
|
||||
function evaluate() {
|
||||
if (!loadedQuestions.length) return;
|
||||
var percentage = scoreLoadedQuestions();
|
||||
$("#percentage").html("Eredmény: " + percentage + "%");
|
||||
$("#state").html("Válaszok leellenőrizve!");
|
||||
|
||||
if (isLocal && !reviewMode) {
|
||||
saveResult(percentage);
|
||||
reviewMode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// "Helyes megoldások": reveal the correct answers. This is a review action, so
|
||||
// we enter review mode *before* grading to guarantee it can never overwrite a
|
||||
// previously saved result.
|
||||
function showCorrect() {
|
||||
if (!loadedQuestions.length) return;
|
||||
reviewMode = 1;
|
||||
var percentage = scoreLoadedQuestions();
|
||||
loadedQuestions.forEach(function (question) {
|
||||
$("#label" + question.id + ".rad" + question.correct).css(
|
||||
"background-color",
|
||||
"#C6FF8C",
|
||||
);
|
||||
});
|
||||
$("#percentage").html("Eredmény: " + percentage + "%");
|
||||
$("#state").html("Helyes válaszok bejelölve!");
|
||||
$("#state2").show();
|
||||
$("#state2").html(
|
||||
"(Ellenőrző mód, az itteni eredményeid nem kerülnek elmentésre, a módból való kilépéshez tölts be egy új tesztsort!)",
|
||||
);
|
||||
}
|
||||
|
||||
function teszt(id, correctAns) {
|
||||
var div = "#feladat" + id;
|
||||
var correct = "#form" + id + " #rad" + correctAns;
|
||||
var isCorrect = $(correct).is(":checked");
|
||||
currentPoints++;
|
||||
if (isCorrect) {
|
||||
$(div).animate({ backgroundColor: "#C6FF8C" }, 1100);
|
||||
correctAnswersGiven++;
|
||||
} else {
|
||||
$(div).animate({ backgroundColor: "#FF808C" }, 1100);
|
||||
}
|
||||
if (currentPoints >= totalPoints) {
|
||||
var percentage = (correctAnswersGiven / totalPoints) * 100;
|
||||
percentage = Math.round(percentage * 100) / 100;
|
||||
percentage = percentage.toFixed(2);
|
||||
$("#percentage").html("Eredmény: " + percentage + "%");
|
||||
$("#state").html("Válaszok leellenőrizve!");
|
||||
if (isLocal && !reviewMode) {
|
||||
function saveResult(percentage) {
|
||||
var datum = new Date();
|
||||
var ido = Math.round(timer / 60);
|
||||
eval(
|
||||
"localStorage.teszt" +
|
||||
numberOfPreviousTests +
|
||||
" = '" +
|
||||
percentage +
|
||||
"'",
|
||||
);
|
||||
eval(
|
||||
"localStorage.teszt" +
|
||||
numberOfPreviousTests +
|
||||
"date = '" +
|
||||
datum.toLocaleDateString() +
|
||||
"'",
|
||||
);
|
||||
eval(
|
||||
"localStorage.teszt" + numberOfPreviousTests + "time = '" + ido + "'",
|
||||
);
|
||||
eval(
|
||||
"localStorage.teszt" +
|
||||
numberOfPreviousTests +
|
||||
"total = '" +
|
||||
totalPoints +
|
||||
"'",
|
||||
);
|
||||
localStorage["teszt" + numberOfPreviousTests] = percentage;
|
||||
localStorage["teszt" + numberOfPreviousTests + "date"] =
|
||||
datum.toLocaleDateString();
|
||||
localStorage["teszt" + numberOfPreviousTests + "time"] = ido;
|
||||
localStorage["teszt" + numberOfPreviousTests + "total"] = totalPoints;
|
||||
startTimer = 0;
|
||||
timer = 0;
|
||||
$("#state2").show();
|
||||
|
|
@ -183,20 +191,6 @@ function teszt(id, correctAns) {
|
|||
"Eredményed mentésre került! Ellenőrző módba belépve az eredményeid nem kerülnek tárolásra. A módból való kilépéshez tölts be egy új tesztsort!",
|
||||
);
|
||||
eredmeny();
|
||||
reviewMode = 1;
|
||||
}
|
||||
currentPoints = 0;
|
||||
correctAnswersGiven = 0;
|
||||
}
|
||||
}
|
||||
|
||||
function scrollTo(where) {
|
||||
$("html, body").animate(
|
||||
{
|
||||
scrollTop: $(where).offset().top - 100,
|
||||
},
|
||||
1000,
|
||||
);
|
||||
}
|
||||
|
||||
function howMany() {
|
||||
|
|
@ -266,28 +260,13 @@ setInterval(function () {
|
|||
$(document).ready(function () {
|
||||
eredmeny();
|
||||
|
||||
// Initialize year dropdown with dynamic years from question data
|
||||
if (typeof initializeYearDropdown === "function") {
|
||||
initializeYearDropdown().then(() => {
|
||||
// Initialize month dropdown for default "all" year selection
|
||||
if (typeof initializeMonthDropdown === "function") {
|
||||
initializeMonthDropdown("all/");
|
||||
}
|
||||
});
|
||||
}
|
||||
// Populate the year dropdown, then the month dropdown for the default "all".
|
||||
initializeYearDropdown().then(() => initializeMonthDropdown("all/"));
|
||||
|
||||
$(window).on("mousewheel", function () {
|
||||
$("body").stop();
|
||||
});
|
||||
|
||||
$(document).ajaxError(function (event, jqxhr, settings) {
|
||||
if (!settings.secondExec) {
|
||||
settings.secondExec = true;
|
||||
setTimeout(function () {
|
||||
$.ajax(settings);
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
aspect();
|
||||
|
||||
$("#bfooldal").click(function () {
|
||||
|
|
@ -333,36 +312,7 @@ $(document).ready(function () {
|
|||
isSearch = false;
|
||||
});
|
||||
$("#evszam").change(function () {
|
||||
const selectedYear = $("#evszam").val();
|
||||
|
||||
// Initialize month dropdown dynamically based on selected year
|
||||
if (typeof initializeMonthDropdown === "function") {
|
||||
initializeMonthDropdown(selectedYear);
|
||||
} else {
|
||||
// Fallback to original logic if dynamic function not available
|
||||
if (selectedYear == "2006/") {
|
||||
$(".f2006").show();
|
||||
$(".f2016").hide();
|
||||
$(".f").hide();
|
||||
$(".fnem17").hide();
|
||||
} else if (selectedYear == "2016/") {
|
||||
$(".f2006").hide();
|
||||
$(".f2016").show();
|
||||
$(".f").show();
|
||||
$(".fnem17").show();
|
||||
} else if (selectedYear == "2017/") {
|
||||
$(".f2006").hide();
|
||||
$(".f2016").hide();
|
||||
$(".f").show();
|
||||
$(".fnem17").hide();
|
||||
} else {
|
||||
$(".f2006").hide();
|
||||
$(".f2016").hide();
|
||||
$(".f").show();
|
||||
$(".fnem17").show();
|
||||
}
|
||||
}
|
||||
|
||||
initializeMonthDropdown($("#evszam").val());
|
||||
$("#honap").val("all");
|
||||
});
|
||||
|
||||
|
|
@ -391,6 +341,14 @@ $(document).ready(function () {
|
|||
$("#load").click(function (event) {
|
||||
ajaxLoad(isSearch ? 1 : 3);
|
||||
});
|
||||
$("#ans").click(function (event) {
|
||||
event.preventDefault();
|
||||
evaluate();
|
||||
});
|
||||
$("#cAns").click(function (event) {
|
||||
event.preventDefault();
|
||||
showCorrect();
|
||||
});
|
||||
$(".scroll").click(function () {
|
||||
$("body").animate(
|
||||
{
|
||||
|
|
|
|||
|
|
@ -72,13 +72,24 @@ const loadQuestions = async (
|
|||
);
|
||||
}
|
||||
|
||||
resultHtml = "";
|
||||
|
||||
currentQuestions = currentQuestions.slice(0, questionCount);
|
||||
|
||||
// Remember the exact set being shown. The two action buttons ("Kiértékelés"
|
||||
// and "Helyes megoldások") are bound once in fizika.js and grade this whole
|
||||
// set in a single pass. Previously each question injected its own #ans/#cAns
|
||||
// click handler; those were never removed, so they piled up across loads and
|
||||
// ended up grading stale (already-removed) questions, saving bogus 0%
|
||||
// results over the user's history.
|
||||
loadedQuestions = currentQuestions.map(({ id, correct }) => ({
|
||||
id: Number(id),
|
||||
correct: Number(correct),
|
||||
}));
|
||||
totalPoints = loadedQuestions.length;
|
||||
|
||||
let resultHtml = "";
|
||||
currentQuestions.forEach(
|
||||
({ id, source, description, a, b, c, d, correct, image }, i) => {
|
||||
({ id, source, description, a, b, c, d, image }, i) => {
|
||||
const qid = Number(id);
|
||||
const correctAnswer = Number(correct);
|
||||
const safeImage = image ? encodeURIComponent(image) : "";
|
||||
resultHtml += `
|
||||
<div class="feladat card" id="feladat${qid}">
|
||||
|
|
@ -104,31 +115,15 @@ const loadQuestions = async (
|
|||
: ""
|
||||
}
|
||||
</form>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
totalPoints++;
|
||||
$("#ans").click(function(event){
|
||||
event.preventDefault();
|
||||
teszt(${qid}, ${correctAnswer});
|
||||
});
|
||||
$("#cAns").click(function(event){
|
||||
event.preventDefault();
|
||||
showCorrect(${qid}, ${correctAnswer});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
`;
|
||||
},
|
||||
);
|
||||
|
||||
resultHtml +=
|
||||
currentQuestions.length === 0
|
||||
? '<div class="buttonwrapper"><b style="font-size: 2rem;">Nem található a keresésnek megfelelő feladat!</b></div>'
|
||||
: `<script type="text/javascript">
|
||||
startTimer = 1;
|
||||
timer = 0;
|
||||
</script>`;
|
||||
if (currentQuestions.length === 0) {
|
||||
resultHtml =
|
||||
'<div class="buttonwrapper"><b style="font-size: 2rem;">Nem található a keresésnek megfelelő feladat!</b></div>';
|
||||
}
|
||||
|
||||
return resultHtml;
|
||||
};
|
||||
|
|
@ -200,7 +195,7 @@ const initializeMonthDropdown = (selectedYear) => {
|
|||
// Convert to sorted array and create options
|
||||
const uniqueMonths = Array.from(monthSet).sort();
|
||||
uniqueMonths.forEach((month) => {
|
||||
monthOptions += `<option value="${month}" class="fdynamic">${getMonthLabel(month)}</option>`;
|
||||
monthOptions += `<option value="${month}">${getMonthLabel(month)}</option>`;
|
||||
});
|
||||
} else {
|
||||
// Extract year from selected value (e.g., "2024/" -> "2024")
|
||||
|
|
@ -220,44 +215,39 @@ const initializeMonthDropdown = (selectedYear) => {
|
|||
// Special handling for known year patterns
|
||||
if (year === "2006") {
|
||||
// Preserve existing 2006 logic but add any new months found
|
||||
monthOptions +=
|
||||
'<option value="1" class="f2006">Február-Március</option>';
|
||||
monthOptions += '<option value="2" class="f2006">Május-Június</option>';
|
||||
monthOptions +=
|
||||
'<option value="3" class="f2006">Október-November</option>';
|
||||
monthOptions += '<option value="1">Február-Március</option>';
|
||||
monthOptions += '<option value="2">Május-Június</option>';
|
||||
monthOptions += '<option value="3">Október-November</option>';
|
||||
|
||||
// Add any dynamic months not covered by the standard ones
|
||||
uniqueMonths.forEach((month) => {
|
||||
if (!["1", "2", "3"].includes(month)) {
|
||||
monthOptions += `<option value="${month}" class="f2006">${getMonthLabel(month)}</option>`;
|
||||
monthOptions += `<option value="${month}">${getMonthLabel(month)}</option>`;
|
||||
}
|
||||
});
|
||||
} else if (year === "2016") {
|
||||
// Preserve existing 2016 logic but add any new months found
|
||||
monthOptions += '<option value="1" class="f">Május-Június</option>';
|
||||
monthOptions += '<option value="2" class="f">Október-November</option>';
|
||||
monthOptions +=
|
||||
'<option value="m1" class="f2016">1. Mintafeladatsor</option>';
|
||||
monthOptions +=
|
||||
'<option value="m2" class="f2016">2. Mintafeladatsor</option>';
|
||||
monthOptions +=
|
||||
'<option value="m3" class="f2016">3. Mintafeladatsor</option>';
|
||||
monthOptions += '<option value="1">Május-Június</option>';
|
||||
monthOptions += '<option value="2">Október-November</option>';
|
||||
monthOptions += '<option value="m1">1. Mintafeladatsor</option>';
|
||||
monthOptions += '<option value="m2">2. Mintafeladatsor</option>';
|
||||
monthOptions += '<option value="m3">3. Mintafeladatsor</option>';
|
||||
|
||||
// Add any dynamic months not covered
|
||||
uniqueMonths.forEach((month) => {
|
||||
if (!["1", "2", "m1", "m2", "m3"].includes(month)) {
|
||||
monthOptions += `<option value="${month}" class="f">${getMonthLabel(month)}</option>`;
|
||||
monthOptions += `<option value="${month}">${getMonthLabel(month)}</option>`;
|
||||
}
|
||||
});
|
||||
} else if (year === "2017") {
|
||||
// Preserve existing 2017 logic but add any new months found
|
||||
monthOptions += '<option value="1" class="f">Május-Június</option>';
|
||||
monthOptions += '<option value="2" class="f">Október-November</option>';
|
||||
monthOptions += '<option value="1">Május-Június</option>';
|
||||
monthOptions += '<option value="2">Október-November</option>';
|
||||
|
||||
// Add any dynamic months
|
||||
uniqueMonths.forEach((month) => {
|
||||
if (!["1", "2"].includes(month)) {
|
||||
monthOptions += `<option value="${month}" class="f">${getMonthLabel(month)}</option>`;
|
||||
monthOptions += `<option value="${month}">${getMonthLabel(month)}</option>`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
|
@ -266,16 +256,16 @@ const initializeMonthDropdown = (selectedYear) => {
|
|||
const hasStandard2 = uniqueMonths.includes("2");
|
||||
|
||||
if (hasStandard1) {
|
||||
monthOptions += '<option value="1" class="f">Május-Június</option>';
|
||||
monthOptions += '<option value="1">Május-Június</option>';
|
||||
}
|
||||
if (hasStandard2) {
|
||||
monthOptions += '<option value="2" class="f">Október-November</option>';
|
||||
monthOptions += '<option value="2">Október-November</option>';
|
||||
}
|
||||
|
||||
// Add any non-standard months
|
||||
uniqueMonths.forEach((month) => {
|
||||
if (!["1", "2"].includes(month)) {
|
||||
monthOptions += `<option value="${month}" class="f">${getMonthLabel(month)}</option>`;
|
||||
monthOptions += `<option value="${month}">${getMonthLabel(month)}</option>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
2
frontend/js/plausible.js
Normal file
2
frontend/js/plausible.js
Normal file
File diff suppressed because one or more lines are too long
10
frontend/js/stats.js
Normal file
10
frontend/js/stats.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { init } from "./plausible.js";
|
||||
|
||||
init({
|
||||
domain: "fizika.schmelczer.dev",
|
||||
endpoint: "https://stats.schmelczer.dev/status",
|
||||
autoCapturePageviews: true,
|
||||
outboundLinks: true,
|
||||
fileDownloads: true,
|
||||
hashBasedRouting: true,
|
||||
});
|
||||
22
frontend/package-lock.json
generated
Normal file
22
frontend/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"name": "fizika-frontend",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fizika-frontend",
|
||||
"version": "1.0.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@plausible-analytics/tracker": "^0.4.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@plausible-analytics/tracker": {
|
||||
"version": "0.4.5",
|
||||
"resolved": "https://registry.npmjs.org/@plausible-analytics/tracker/-/tracker-0.4.5.tgz",
|
||||
"integrity": "sha512-6BfAGejXY+YA3Cw6LYT2Zpn4hTxDtPQAawFsYUsQCOg78wIS5C4deAGXTfJffa5VleMWITv5lpJ/EYuQBl1tPA==",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
frontend/package.json
Normal file
13
frontend/package.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "fizika-frontend",
|
||||
"version": "1.0.0",
|
||||
"description": "Static frontend for the Fizika practice app",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"vendor": "cp node_modules/@plausible-analytics/tracker/plausible.js js/plausible.js",
|
||||
"postinstall": "npm run vendor"
|
||||
},
|
||||
"dependencies": {
|
||||
"@plausible-analytics/tracker": "^0.4.5"
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue