This commit is contained in:
2026-08-19 19:06:41 +02:00
parent 51d61c1255
commit cda5108189
5 changed files with 48 additions and 3 deletions
Regular → Executable
View File
+1 -1
View File
@@ -1,4 +1,4 @@
const SHELL_CACHE='fixfin-shell-v3.19';
const SHELL_CACHE='fixfin-shell-v3.20';
const DATA_CACHE='fixfin-data-v1';
const APP_SHELL=['/','/manifest.webmanifest','/icons/icon-192.png','/icons/icon-512.png','/icons/apple-touch-icon.png'];
+18
View File
@@ -21,6 +21,22 @@ function parseAmount(value) {
const number = Number(normalized);
return Number.isFinite(number) ? number : Number.NaN;
}
let modalLockDepth = 0;
function useModalScrollLock() {
useEffect(() => {
modalLockDepth += 1;
document.documentElement.classList.add('modal-open');
document.body.classList.add('modal-open');
return () => {
modalLockDepth = Math.max(0, modalLockDepth - 1);
if (modalLockDepth === 0) {
document.documentElement.classList.remove('modal-open');
document.body.classList.remove('modal-open');
}
};
}, []);
}
function uid() {
if (globalThis.crypto?.randomUUID) return globalThis.crypto.randomUUID();
if (globalThis.crypto?.getRandomValues) {
@@ -578,6 +594,7 @@ function ScenariosPage({data,persist}){
}
function ScenarioAdjustmentDialog({data,item,onClose,onSave}){
useModalScrollLock();
const [name,setName]=useState(item?.name||''); const [type,setType]=useState(item?.type||'expense'); const [amount,setAmount]=useState(item?.amount??'');
const [accountId,setAccountId]=useState(item?.accountId||data.accounts[0]?.id||''); const [fromAccountId,setFromAccountId]=useState(item?.fromAccountId||data.accounts[0]?.id||''); const [toAccountId,setToAccountId]=useState(item?.toAccountId||data.accounts[1]?.id||data.accounts[0]?.id||''); const [personId,setPersonId]=useState(item?.personId||''); const [error,setError]=useState('');
function submit(e){e.preventDefault();const numeric=parseAmount(amount);if(!name.trim())return setError('Bitte eine Bezeichnung eingeben.');if(!Number.isFinite(numeric)||numeric<0)return setError('Bitte einen gültigen Betrag eingeben.');if(!personId)return setError('Bitte eine Person auswählen.');if(type==='transfer'&&fromAccountId===toAccountId)return setError('Quell- und Zielkonto müssen verschieden sein.');const value={id:item?.id||uid(),name:name.trim(),type,amount:numeric,personId:personId||null};if(type==='transfer'){value.fromAccountId=fromAccountId;value.toAccountId=toAccountId;}else value.accountId=accountId;onSave(value);}
@@ -635,6 +652,7 @@ function DataPage({data,importFile}){
function Empty({text}){return <div className="empty">{text}</div>}
function EditorDialog({dialog,data,onClose,onSave}){
useModalScrollLock();
const type=dialog.type,item=dialog.item; const editing=Boolean(item?.id);
const [name,setName]=useState(item?.name||''),[amount,setAmount]=useState(item?.amount??''),[accountId,setAccountId]=useState(item?.accountId||data.accounts[0]?.id||''),[fromAccountId,setFromAccountId]=useState(item?.fromAccountId||data.accounts[0]?.id||''),[toAccountId,setToAccountId]=useState(item?.toAccountId||data.accounts[1]?.id||data.accounts[0]?.id||''),[interval,setInterval]=useState(item?.interval||'monthly'),[dueMonth,setDueMonth]=useState(item?.dueMonth?String(item.dueMonth):''),[categoryId,setCategoryId]=useState(item?.categoryId||''),[newCategoryName,setNewCategoryName]=useState(''),[personId,setPersonId]=useState(item?.personId||''),[newPersonName,setNewPersonName]=useState(''),[pushoverReminder,setPushoverReminder]=useState(item?.pushoverReminder===true),[endDate,setEndDate]=useState(item?.endDate||''),[amountChanges,setAmountChanges]=useState(Array.isArray(item?.amountChanges)?item.amountChanges:[]),[changeDate,setChangeDate]=useState(''),[changeAmount,setChangeAmount]=useState(''),[localError,setLocalError]=useState('');
const labels={accounts:'Konto',categories:'Kategorie',persons:'Person',incomes:'Eingang',expenses:'Ausgang',transfers:'Transfer'};
+29 -2
View File
@@ -80,8 +80,8 @@ tbody tr:last-child td { border-bottom:0; }
.button-row { display:flex;gap:10px;flex-wrap:wrap; }
.button-link { text-decoration:none;display:inline-flex;align-items:center;cursor:pointer; }
.json-preview { margin:0;max-height:420px;overflow:auto;background:#0a0f17;border:1px solid #202a39;border-radius:12px;padding:14px;font-size:11px;color:#abb8c8; }
.modal-backdrop { position:fixed;inset:0;background:#02050abf;display:grid;place-items:center;padding:20px;z-index:50;backdrop-filter:blur(5px); }
.modal { width:min(470px,100%);background:#111722;border:1px solid #334158;border-radius:18px;padding:20px;box-shadow:0 30px 100px #0009; }
.modal-backdrop { position:fixed;inset:0;background:#02050abf;display:grid;place-items:center;padding:20px;z-index:50;backdrop-filter:blur(5px);overflow:hidden;overscroll-behavior:contain; }
.modal { width:min(470px,100%);max-height:calc(100dvh - 40px);overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;background:#111722;border:1px solid #334158;border-radius:18px;padding:20px;box-shadow:0 30px 100px #0009; }
.modal-head { display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:18px; }
.modal-head h2 { font-size:24px;margin-top:3px; }
.close { background:transparent;color:#8b99ab;font-size:24px;padding:2px 8px;border:0; }
@@ -97,6 +97,33 @@ tbody tr:last-child td { border-bottom:0; }
.loading { min-height:100vh;display:grid;place-items:center;color:#94a3b8; }
code { color:#b8c3ff; }
html.modal-open, body.modal-open { overflow:hidden !important; overscroll-behavior:none; }
@media (max-width: 760px) {
.modal-backdrop {
display:flex;
align-items:center;
justify-content:center;
padding:max(10px, env(safe-area-inset-top)) 10px max(10px, env(safe-area-inset-bottom));
}
.modal {
width:100%;
max-height:calc(100dvh - max(20px, env(safe-area-inset-top)) - max(20px, env(safe-area-inset-bottom)));
padding:18px;
border-radius:17px;
}
.modal-actions {
position:sticky;
bottom:-18px;
z-index:6;
margin:20px -18px -18px;
padding:12px 18px calc(12px + env(safe-area-inset-bottom));
background:linear-gradient(180deg,#111722e8 0%,#111722 28%);
border-top:1px solid #263246;
}
.modal-actions button { min-height:44px; }
}
@media (max-width: 1050px) {
.summary-grid { grid-template-columns:1fr 1fr; }
.account-summary-grid { grid-template-columns:1fr 1fr; }
Regular → Executable
View File