mirror of
https://github.com/gauvainboiche/ketapk.git
synced 2026-09-02 11:13:11 +02:00
refacto: Making Tailwind offline + making it Tauri compatible for compilation
This commit is contained in:
@@ -0,0 +1 @@
|
||||
@import "tailwindcss";
|
||||
@@ -57,4 +57,40 @@ input[type="number"] {
|
||||
#pkChart {
|
||||
min-height: 280px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Annulation des flèches sur les numéros */
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
input[type="number"] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
/* Scrollbar timeline */
|
||||
#timelineGrid::-webkit-scrollbar {
|
||||
height: 8px;
|
||||
}
|
||||
#timelineGrid::-webkit-scrollbar-track {
|
||||
background: rgba(15, 23, 42, 0.6);
|
||||
border-radius: 9999px;
|
||||
}
|
||||
#timelineGrid::-webkit-scrollbar-thumb {
|
||||
background: rgba(51, 65, 85, 0.8);
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
/* Transitions modale */
|
||||
#modalCalc {
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
#modalCalc.hidden {
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
#modalCalc:not(.hidden) {
|
||||
opacity: 1;
|
||||
pointer-events: auto;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
+8
-10
@@ -5,18 +5,16 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>KétaPK - Simulation Pharmacocinétique</title>
|
||||
|
||||
<!-- Tailwind CSS -->
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<!-- CSS Tailwind compilé (Léger, rapide, hors-ligne) -->
|
||||
<link rel="stylesheet" href="css/tailwind.css">
|
||||
|
||||
<!-- Chart.js + Plugins -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@3.0.1/dist/chartjs-plugin-annotation.min.js"></script>
|
||||
|
||||
<!-- jsPDF -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<!-- CSS Personnalisé -->
|
||||
<link rel="stylesheet" href="css/styles.css">
|
||||
|
||||
<!-- Librairies JS Statiques -->
|
||||
<script src="vendor/chart.umd.min.js"></script>
|
||||
<script src="vendor/chartjs-plugin-annotation.min.js"></script>
|
||||
<script src="vendor/jspdf.umd.min.js"></script>
|
||||
</head>
|
||||
<body class="h-full flex flex-col font-sans antialiased selection:bg-amber-500 selection:text-slate-950">
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { MODES, PK_MODELS, CLINICAL_THRESHOLDS, generateSimulationData } from '/pkCore.js';
|
||||
import { MODES, PK_MODELS, CLINICAL_THRESHOLDS, generateSimulationData } from './pkCore.js';
|
||||
import { adjustChartYScale } from './chartManager.js';
|
||||
import { initCalculatorUI } from './calculator.js';
|
||||
import { generatePDFReport } from './pdfExport.js';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CalculatorEngine } from '/pkCore.js';
|
||||
import { CalculatorEngine } from './pkCore.js';
|
||||
|
||||
export function initCalculatorUI() {
|
||||
const modal = document.getElementById('modalCalc');
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CLINICAL_THRESHOLDS } from '/pkCore.js';
|
||||
import { CLINICAL_THRESHOLDS } from './pkCore.js';
|
||||
import { t } from './i18n.js';
|
||||
|
||||
export function updateChartAnnotations(chart, mode, currentYMax) {
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* ============================================================================
|
||||
* KétaPK - Moteur Pharmacocinétique (PK/PD)
|
||||
* Modèles : Domino (1982), Clements (1981), Kamp (2020)
|
||||
* ============================================================================
|
||||
*/
|
||||
|
||||
export const MODES = {
|
||||
ESKETAMINE: 'ESKETAMINE',
|
||||
RACEMIQUE: 'RACEMIQUE'
|
||||
};
|
||||
|
||||
// Modèles Multi-exponentiels
|
||||
export const PK_MODELS = {
|
||||
DOMINO: {
|
||||
name: "Domino (1982)",
|
||||
refDose: 2.0,
|
||||
A: 14300, alpha: 1.35167,
|
||||
B: 2340, beta: 0.09517,
|
||||
C: 197, gamma: 0.00378,
|
||||
color: '#ff9933'
|
||||
},
|
||||
CLEMENTS: {
|
||||
name: "Clements (1981)",
|
||||
refDose: 0.25,
|
||||
A: 108, alpha: 0.03940,
|
||||
B: 39, beta: 0.00380,
|
||||
C: 0, gamma: 0,
|
||||
color: '#6ec46c'
|
||||
},
|
||||
KAMP: {
|
||||
name: "Kamp (2020)",
|
||||
refDose: 0.5,
|
||||
A: 1332, alpha: 0.24658,
|
||||
B: 155, beta: 0.03845,
|
||||
C: 69, gamma: 0.00409,
|
||||
color: '#4fafe3'
|
||||
}
|
||||
};
|
||||
|
||||
// Zones d'effets cliniques et seuils (ng/mL)
|
||||
export const CLINICAL_THRESHOLDS = {
|
||||
[MODES.ESKETAMINE]: {
|
||||
maxScale: 500,
|
||||
defaultConcentration: 5,
|
||||
zones: [
|
||||
{ zoneKey: "inactive", min: 0, max: 10, color: "rgba(249, 252, 126, 0.4)", textHex: "#8a8d00" },
|
||||
{ zoneKey: "anti_hyperalgesic", min: 10, max: 50, color: "rgba(218, 247, 166, 0.4)", textHex: "#417505" },
|
||||
{ zoneKey: "analgesia", min: 50, max: 150, color: "rgba(255, 195, 0, 0.4)", textHex: "#b78100" },
|
||||
{ zoneKey: "psychedelic", min: 150, max: 350, color: "rgba(242, 160, 223, 0.4)", textHex: "#a2137f" },
|
||||
{ zoneKey: "emergence", min: 350, max: 500, color: "rgba(89, 196, 240, 0.4)", textHex: "#0c6796" },
|
||||
{ zoneKey: "narcosis", min: 500, max: 1000, color: "rgba(43, 122, 244, 0.4)", textHex: "#0a3c8a" },
|
||||
{ zoneKey: "excessive", min: 1000, max: Infinity, color: "rgba(255, 87, 51, 0.4)", textHex: "#a81300" }
|
||||
]
|
||||
},
|
||||
[MODES.RACEMIQUE]: {
|
||||
maxScale: 1000,
|
||||
defaultConcentration: 10,
|
||||
zones: [
|
||||
{ zoneKey: "inactive", min: 0, max: 20, color: "rgba(249, 252, 126, 0.4)", textHex: "#8a8d00" },
|
||||
{ zoneKey: "anti_hyperalgesic", min: 20, max: 100, color: "rgba(218, 247, 166, 0.4)", textHex: "#417505" },
|
||||
{ zoneKey: "analgesia", min: 100, max: 300, color: "rgba(255, 195, 0, 0.4)", textHex: "#b78100" },
|
||||
{ zoneKey: "psychedelic", min: 300, max: 700, color: "rgba(242, 160, 223, 0.4)", textHex: "#a2137f" },
|
||||
{ zoneKey: "emergence", min: 700, max: 1000, color: "rgba(89, 196, 240, 0.4)", textHex: "#0c6796" },
|
||||
{ zoneKey: "narcosis", min: 1000, max: 2000, color: "rgba(43, 122, 244, 0.4)", textHex: "#0a3c8a" },
|
||||
{ zoneKey: "excessive", min: 2000, max: Infinity, color: "rgba(255, 87, 51, 0.4)", textHex: "#a81300" }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calcul d'un bolus unique à l'instant t
|
||||
*/
|
||||
export function calculateBolusCp(model, doseMg, weightKg, timeElapsedMin) {
|
||||
if (timeElapsedMin < 0 || weightKg <= 0) return 0;
|
||||
|
||||
const dosePerKg = doseMg / weightKg;
|
||||
const { A, alpha, B, beta, C, gamma } = model;
|
||||
|
||||
const termA = A * Math.exp(-alpha * timeElapsedMin);
|
||||
const termB = B * Math.exp(-beta * timeElapsedMin);
|
||||
const termC = C * (gamma ? Math.exp(-gamma * timeElapsedMin) : 0);
|
||||
|
||||
return dosePerKg * (termA + termB + termC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Superposition Linéaire des Bolus et Perfusions sur 300 min
|
||||
*/
|
||||
export function generateSimulationData({ model, weightKg, timelineInputs }) {
|
||||
const timeGrid = Array.from({ length: 61 }, (_, i) => i * 5);
|
||||
const cpResults = new Array(61).fill(0);
|
||||
|
||||
timeGrid.forEach((targetTime, targetIndex) => {
|
||||
let totalCp = 0;
|
||||
|
||||
for (let i = 0; i <= targetIndex; i++) {
|
||||
const deltaTime = targetTime - timeGrid[i];
|
||||
const input = timelineInputs[i] || { bolusMg: 0, perfRateMgKgH: 0 };
|
||||
|
||||
if (input.bolusMg > 0) {
|
||||
totalCp += calculateBolusCp(model, input.bolusMg, weightKg, deltaTime);
|
||||
}
|
||||
|
||||
if (input.perfRateMgKgH > 0) {
|
||||
const perfDoseMg = (input.perfRateMgKgH * weightKg) * (5 / 60);
|
||||
totalCp += calculateBolusCp(model, perfDoseMg, weightKg, deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
cpResults[targetIndex] = Math.round(totalCp * 100) / 100;
|
||||
});
|
||||
|
||||
return cpResults;
|
||||
}
|
||||
|
||||
// Moteur de conversion de doses
|
||||
export const CalculatorEngine = {
|
||||
mgToMgKg: (mg, weight) => (weight > 0 ? mg / weight : 0),
|
||||
mgKgToMg: (mgKg, weight) => mgKg * weight,
|
||||
mgKgHToMicrogKgMin: (mgKgH) => (mgKgH * 1000) / 60,
|
||||
microgKgMinToMgKgH: (microg) => (microg * 60) / 1000
|
||||
};
|
||||
Vendored
+20
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+398
File diff suppressed because one or more lines are too long
Vendored
+83
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user