diff --git a/TODO.md b/TODO.md index dabf723..208c1bc 100644 --- a/TODO.md +++ b/TODO.md @@ -27,21 +27,19 @@ - musste den clip-path von tr und td auf none setzen - x jetzt kann ich den damage-monitor zwar aufklappen, aber die Buttons der weiter unten liegenden combatant-rows überdecken ihn jedesmal. - x wenn ich einen Damage-Button anklicke, beginnt die Transition des damage-monitor von Neuem - -- Output vom HTML Validator: +- x wenn die Navbar borders hat, sollte sie nicht direkt am oberen Bildrand anfangen, sondern ein paar Pixel weiter unten +- x Unterschied zwischen enabled und disabled button nicht gut erkennbar +- x Output vom HTML Validator: - img elements müssen alt attributes haben - The form attribute must refer to a form element. (bei den Input Elementen im combatant-modal) -> muss nachsehen, was ich dann genau da eintragen muss -- wenn die Navbar borders hat, sollte sie nicht direkt am oberen Bildrand anfangen, sondern ein paar Pixel weiter unten + - nach dem Laden passiert es manchmal, dass nach dem Einfügen von testCombatant das add Modal gleich wieder aufgeht - schien die gleiche Sache zu sein wie mit dem hidden.bs.modal event - jetzt kommt es aber trotzdem manchmal wieder - vllt. ein timeout-Problem? - add modal geht bei enter key nicht zu -> liegt daran, dass ich nicht mehr .modal("hide") verwende - ich könnt's umstellen, aber will ich das? -- Unterschied zwischen enabled und disabled button nicht gut erkennbar - wenn ein damage monitor offen ist und ich auf add combatant clicke, springt der Fokus nicht zuverlässig ins erste input feld -- navbar bei größerem viewport -- brand-name nicht mittig - Bug: rea editieren ändert nicht die ini -> da muss ich die Würfelergebnisse für speichern @@ -52,7 +50,25 @@ - Verwalte sie jetzt komplett mit der data-* API; verwende dafür ausschließlich .attr() als Getter/Setter - Füge die Werte aus dem Attribut per CSS direkt ins Element ein (::after und content). - x prettify code: alle HTML class names von camelCale zu dash-case komvertieren -- neue Icons: act add cross damage dice edit newround trash zzz clone +- x Design cyberpunkig machen +- x im modal soll man die damage levels einstellen/verändern können + - input type=range + - Werte sollen dazu angezeigt werden -> https://stackoverflow.com/questions/26612700/ticks-for-type-range-html-input#26613443 + - ein label über die range, eins darunter +- x Im modal, wenn ich die wound penalties anzeige, die Fälle KO und Tod gesondert behandeln +- x clone button + - x und im combatant-modal ein weiterer OK-Button, der das Modal offenlässt + +- noch mehr Design + - favicon -> https://stackoverflow.com/questions/48956465/favicon-standard-2023-svg-ico-png-and-dimensions + - imput[type=range] schicker machen + - input elements styling anpassen für :focus. :focus-visible, :valid, :invalid + - Seite für größere Screens anpassen + - Schrift, Buttons und Icons skalieren + - Tabellenbreite begrenzen + - styling der contextual classes, disabled elements etc. + - Animationen? Transitions? +- neue Icons: (act) add clone dead takedamage die rolldice edit newround trash zzz menu, ggf. favicon - attribution - noun project: Icons by Febrian Hidayat from Noun Project - iconfinder: CC4.0 @@ -61,10 +77,8 @@ - warum sind im dist/-Folder immer zwei Versionen der gleichen Datei? - HTML soll nicht in eine Zeile umgedingst werden, das sieht doch nicht aus - bootstrap, jquery etc lokal vorhalten? -- Im modal, wenn ich die wound penalties anzeige, die Fälle KO und Tod gesondert behandeln -- im modal soll man die damage levels einstellen/verändern können -- "clone this combatant" button: - Anzeige, wieviele Aktionen einer hat u.d wieviele davon schon verbraucht sind -- Design cyberpunkig machen - docstrings - \ No newline at end of file +- parcel soll aus dem HTML code nicht die Newlines rausnehmen -> macht er das überhaupt noch? + - falls ja: .htmlnanorc anlegen, s. https://parceljs.org/languages/html/#minification und https://htmlnano.netlify.app/modules#collapsewhitespace +- progressive web app draus machen? -> https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps/Introduction \ No newline at end of file diff --git a/src/css/custom.scss b/src/css/custom.scss index b22cacb..4426ad7 100644 --- a/src/css/custom.scss +++ b/src/css/custom.scss @@ -26,12 +26,23 @@ $sr2-fg: deeppink; @mixin button() { border: 0; border-radius: 1px; - padding-right: 2px; - padding-left: 2px; + padding-inline: 0px; border: 1px solid cyan; background: transparent; box-shadow: 0 0 2px lightcyan, 0 0 4px cyan, 0 0 8px darkcyan; + + color: deeppink; + + img { + filter: invert(34%) sepia(78%) saturate(7014%) hue-rotate(316deg) brightness(95%) contrast(105%); + } +} + +.sr2-button:focus-visible { + outline: none; + border: 2px solid cyan !important; + box-shadow: 0 0 4px lightcyan, 0 0 8px cyan, 0 0 16px darkcyan !important; } html, @@ -51,14 +62,13 @@ body { } -:focus-visible { - outline: none; - border: 2px solid cyan !important; - box-shadow: 0 0 4px lightcyan, 0 0 8px cyan, 0 0 16px darkcyan !important; +div.container { + position: relative; + padding: 4px; } header.navbar { - margin-top: 4px; +// margin-top: 4px; padding-right: .6rem;; @include border; @include inlay; @@ -78,18 +88,16 @@ header.navbar { button { @include button; + width: 38px; + height: 38px; margin-right: 3px; margin-left: 3px; - > img { - filter: invert(34%) sepia(78%) saturate(7014%) hue-rotate(316deg) brightness(95%) contrast(105%); - } } } - -div.container { - position: relative; +.table-responsive { + margin-bottom: 1px; } #combatants-table { @@ -163,20 +171,36 @@ div.container { --aug-border-bottom: 2px; } - > tbody > tr > td > button, - > tbody > tr > td > div > button, { + .sr2-button { @include button; - padding: 0px; +// padding: 1px; width: 24px; height: 24px; + img { position: relative; bottom: 3px; width: 16px; height: 16px; - filter: invert(34%) sepia(78%) saturate(7014%) hue-rotate(316deg) brightness(75%) contrast(105%); } + + &:disabled { + box-shadow: none; + border-color: darkcyan; + + img { + filter: invert(6%) sepia(93%) saturate(7363%) hue-rotate(2deg) brightness(80%) contrast(105%); + } + + } + } + + .act-button { + line-height: 24px; + font-size: 12px; + position: relative; + bottom: 1px } } @@ -223,11 +247,11 @@ div.container { width: 20px; } -.damage-dropdown { +.damage-dropdown, .actions-dropdown { display: inline-block; } -.damage-monitor { +.damage-monitor, .actions-menu { position: absolute; z-index: 200; @@ -241,7 +265,9 @@ div.container { padding-top: 10px; padding-bottom: 10px; +} +.damage-monitor { button { font-size: smaller; width: 24px; @@ -250,6 +276,11 @@ div.container { border: none; margin: 0px 2px; border-radius: 0; + + &:focus-visible { + filter: brightness(150%) !important; + outline: none; + } } .damage-stun { @@ -268,6 +299,10 @@ div.container { background: radial-gradient(circle at center, deeppink, maroon); box-shadow: none; transition: background .5s, box-shadow .5s; + + &:focus-visible { + outline: deeppink !important; + } } .damage-physical.active { @@ -275,13 +310,6 @@ div.container { box-shadow: 0 0 3px lightpink, 0 0 6px deeppink, 0 0 12px maroon; } - .remove-button { - width: 56px; - height: 28px; - margin-top: 4px; - @include button; - } - td button img { position: relative; top: -2px; @@ -298,6 +326,60 @@ div.container { */ } +.actions-menu { + display: flex; + flex-flow: column; + padding: 6px; + + + button { + @include button; + width: 24px; + height: 24px; + margin: 4px; + + img { + position: relative; + bottom: 3px; + width: 16px; + height: 16px; + } + } +} + + +.footer-container { + position: fixed; + left: 0px; + right: 0px; + bottom: 0px; +} +footer { +// z-index: -10 !important; + + @include aug; + @include inlay; + --aug-tl: 10px; + --aug-tr: 10px; + --aug-border-bg: cyan !important; // "sr2-border doesn't work" + --aug-border-opacity: .5 !important; + --aug-border-all: 2px !important; + --aug-inlay-bg: rgba(0, 0, 0, .75) !important; + + p { + font-size: xx-small; + margin: .25rem; + color: cyan; + user-select: auto; + + a { + color: hotpink; + text-decoration: none; + } + } + +} + .sr2-modal { @include border; @@ -305,6 +387,10 @@ div.container { color: cyan; pointer-events: auto; + button { + @include button; + } + .modal-header { text-transform: uppercase; border-bottom: none; @@ -334,8 +420,26 @@ div.container { } } + label { + margin: 0; + } + + .label-swap { + display: flex; + flex-flow: column; + + label { + order: 2; + text-align: right; + } + + input { + order: 1; + } + + } + input { - @include button; background-color: transparent; color: deeppink; user-select: text; @@ -350,6 +454,18 @@ div.container { color: deeppink; } + &:focus-visible { + background-color: transparent; + color: deeppink; + } + + &:valid { + } + &:invalid { + border: 1px solid deeppink; + box-shadow: 0 0 3px lightpink, 0 0 6px deeppink, 0 0 12px maroon; + } + &[type=number]::-webkit-inner-spin-button, &[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; @@ -362,16 +478,56 @@ div.container { margin: 0; } - &:invalid { - border: 1px solid deeppink; - box-shadow: 0 0 3px lightpink, 0 0 6px deeppink, 0 0 12px maroon; + &[type=range] { +// -webkit-appearance: none; + width: 91%; + margin-left: calc(4.5% - 2px); + + + datalist { + display: block; + width: 100%; + + option { + display: inline-block; + margin: 0; + width: 9%; + text-align: center; + } + } + + &::-moz-range-track { + height: 2px; + border: 1px; + border-radius: 1px; + } + + &::-moz-range-thumb { + width: 4px; + height: 20px; + } + + &#combatant-modal-stun { + + &::-moz-range-track { + color: darkcyan !important; + } + + &::-moz-range-thumb { + background-color: cyan; + } + } + + &#combatant-modal-physical { + + &::-moz-range-track { + color: maroon; + } + + &::-moz-range-thumb { + background-color: deeppink; + } + } } - - } - - button { - @include button; - color: deeppink; } span.input-group-text { @@ -384,21 +540,12 @@ div.container { -footer { - z-index: -10 !important; - - p { - font-size: x-small; - margin-bottom: .5rem; - } +/* hr { margin: .5rem 0; } -} - -/* th span{ position: absolute; display: block; diff --git a/src/index.html b/src/index.html index fa302b4..d9e8e5c 100644 --- a/src/index.html +++ b/src/index.html @@ -30,17 +30,18 @@ +
- + @@ -50,20 +51,27 @@ + + -
- -
- - \ No newline at end of file diff --git a/src/js/sr2ini.js b/src/js/sr2ini.js index 4560f18..1a9e102 100644 --- a/src/js/sr2ini.js +++ b/src/js/sr2ini.js @@ -8,11 +8,18 @@ const COMBATANT_TABLE_ROW = [ '\n', '\n', '\n', - '\n', ''].join(""); @@ -29,7 +36,7 @@ const DAMAGE_MONITOR_HTML = [ '\n', '\n', '\n', - '\n', +// '\n', '
Name Ini+Ra single die+R Actions
TestD+\n', - '\n', - '\n', + '\n', + '\n', '
\n', - '\n', + '\n', + '
\n', + '
\n', + '\n', + '
\n', + '\n', + '\n', + '\n', + '
\n', '
\n', '
\n', '
'].join(""); const STUN_BADGE_HTML = ''; @@ -99,8 +106,35 @@ function handleActButtonClick(e) { function handleAddButtonClick(e) { // restyle modal $("#combatant-modal .modal-title").text("Add Combatant"); - $("#combatant-modal-add-ok-button").removeClass("d-none"); + $("#combatant-modal-add-ok-button, #combatant-modal-add-apply-button").removeClass("d-none"); $("#combatant-modal-edit-ok-button").addClass("d-none"); + // set damage sliders to zero + $("#combatant-modal-stun, #combatant-modal-physical").val("0"); + // add handler for enter key + $("#combatant-modal input[id*='combatant-modal']").off("keydown"); + $("#combatant-modal input[id*='combatant-modal']").on("keydown", function (e) { + if (e.which == 13 || e.which == 10) { + addCombatant(e); + } + }); +} +// click handler for clone buttons -> like handleAddButtonClick but with a pre-filled modal +function handleCloneButtonClick(e) { + // find current table row + let $tr = $(e.target).parents(".combatant-row"); + // hide actions menu + $tr.find(".actions-menu").addClass("d-none"); + // restyle modal + $("#combatant-modal .modal-title").text("Clone Combatant"); + $("#combatant-modal-add-ok-button, #combatant-modal-add-apply-button").removeClass("d-none"); + $("#combatant-modal-edit-ok-button").addClass("d-none"); + // populate modal with values from row + $("#combatant-modal-name").val($tr.find(".combatant-name").text()); + $("#combatant-modal-dice").val($tr.find(".combatant-dice").attr("data-combatant-dice")); + $("#combatant-modal-rea").val($tr.find(".combatant-rea").attr("data-combatant-rea")); + $("#combatant-modal-ini").val($tr.attr("data-true-ini")); + $("#combatant-modal-stun").val($tr.attr("data-damage-stun") || "0"); + $("#combatant-modal-physical").val($tr.attr("data-damage-physical") || "0"); // add handler for enter key $("#combatant-modal input[id*='combatant-modal']").off("keydown"); $("#combatant-modal input[id*='combatant-modal']").on("keydown", function (e) { @@ -113,8 +147,8 @@ function handleAddButtonClick(e) { function handleDamageButtonClick(e) { // get visibility status at click time let hiddenAtClick = $(e.target).parents(".damage-dropdown").find(".damage-monitor").hasClass("d-none"); - // hide all damage monitors - $(".damage-monitor:visible").addClass("d-none"); + // hide all damage monitors and actions menus + $(".damage-monitor:visible, .actions-menu:visible").addClass("d-none"); // if targeted dm was hidden before, show it now if (hiddenAtClick) { $(e.target).parents(".damage-dropdown").find(".damage-monitor").removeClass("d-none"); @@ -127,16 +161,15 @@ function handleEditButtonClick(e) { let $tr = $(e.target).parents(".combatant-row"); // restyle modal $("#combatant-modal .modal-title").text("Edit Combatant"); - $("#combatant-modal-add-ok-button").addClass("d-none"); + $("#combatant-modal-add-ok-button, #combatant-modal-add-apply-button").addClass("d-none"); $("#combatant-modal-edit-ok-button").removeClass("d-none"); // populate modal with values from row $("#combatant-modal-name").val($tr.find(".combatant-name").text()); $("#combatant-modal-dice").val($tr.find(".combatant-dice").attr("data-combatant-dice")); $("#combatant-modal-rea").val($tr.find(".combatant-rea").attr("data-combatant-rea")); $("#combatant-modal-ini").val($tr.attr("data-true-ini")); - // show effective ini in modal - $("#penalty-stun").text(DAMAGE_PENALTY[parseInt($tr.attr("data-damage-stun")) || 0]); - $("#penalty-physical").text(DAMAGE_PENALTY[parseInt($tr.attr("data-damage-physical")) || 0]); + $("#combatant-modal-stun").val($tr.attr("data-damage-stun") || "0"); + $("#combatant-modal-physical").val($tr.attr("data-damage-physical") || "0"); // mark which row is being edited $("#combatant-modal").data("row", $(".combatant-row").index($tr)); // here it's okay to use .data() b/c HTML/CSS does not care about this value // add handler for enter key @@ -147,6 +180,18 @@ function handleEditButtonClick(e) { } }); } +// click handler for the more-actions menus +function handleMoreActionsButtonClick(e) { + // get visibility status at click time + let hiddenAtClick = $(e.target).parents(".actions-dropdown").find(".actions-menu").hasClass("d-none"); + // hide all damage monitors + $(".actions-menu:visible, .damage-monitor:visible").addClass("d-none"); + // if targeted dm was hidden before, show it now + if (hiddenAtClick) { + $(e.target).parents(".actions-dropdown").find(".actions-menu").removeClass("d-none"); + } + return false; +} function handleNewRoundButton(e) { // restyle modal @@ -184,13 +229,19 @@ function addCombatant(e) { $tr.find(".combatant-name").text($("#combatant-modal-name").val().trim()); $tr.find(".combatant-dice").attr("data-combatant-dice", $("#combatant-modal-dice").val().trim()); $tr.find(".combatant-rea").attr("data-combatant-rea", $("#combatant-modal-rea").val().trim()); - //TODO: retrieve initial damage levels - // add handler to table cells (click to edit) + // retrieve initial damage levels + $tr.attr("data-damage-stun", $("#combatant-modal-stun").val() || "0"); + $tr.find(".damage-stun").addClass("active").slice(0, parseInt($tr.attr("data-damage-stun")) || 0).removeClass("active"); + $tr.attr("data-damage-physical", $("#combatant-modal-physical").val() || "0"); + $tr.find(".damage-physical").addClass("active").slice(0, parseInt($tr.attr("data-damage-physical")) || 0).removeClass("active"); + // add click handler to table cells $tr.find(".combatant-name, .combatant-ini, .combatant-dice-and-rea").on("click", handleEditButtonClick); // add handlers to action buttons - $tr.find("button.edit-button").on("click", handleEditButtonClick); $tr.find("button.act-button").on("click", handleActButtonClick); $tr.find("button.damage-button").on("click", handleDamageButtonClick); + $tr.find("button.actions-button").on("click", handleMoreActionsButtonClick); + $tr.find("button.edit-button").on("click", handleEditButtonClick); + $tr.find("button.clone-button").on("click", handleCloneButtonClick); $tr.find("button.remove-button").on("click", handleRemoveButtonClick); // add handler to damage monitor $tr.find(".damage-stun, .damage-physical").on("click", applyDamage); @@ -243,6 +294,10 @@ function editCombatant(e) { $tr.find(".combatant-name").text(name); $tr.find(".combatant-dice").attr("data-combatant-dice", dice); $tr.find(".combatant-rea").attr("data-combatant-rea", rea); + $tr.attr("data-damage-stun", $("#combatant-modal-stun").val() || "0"); + $tr.find(".damage-stun").addClass("active").slice(0, parseInt($tr.attr("data-damage-stun")) || 0).removeClass("active"); + $tr.attr("data-damage-physical", $("#combatant-modal-physical").val() || "0"); + $tr.find(".damage-physical").addClass("active").slice(0, parseInt($tr.attr("data-damage-physical")) || 0).removeClass("active"); // sort table sortTable(); // clean up @@ -379,10 +434,20 @@ $(document).ready(function () { $("#add-combatant-button").on("click", handleAddButtonClick); $("#new-round-button").on("click", handleNewRoundButton); // add event handlers to modal buttons - $("#combatant-modal-add-ok-button").on("click", addCombatant); + $("#combatant-modal-add-ok-button, #combatant-modal-add-apply-button").on("click", addCombatant); $("#combatant-modal-edit-ok-button").on("click", editCombatant); $("#confirm-modal-new-round-ok-button").on("click", startNewRound); $("#confirm-modal-remove-combatant-ok-button").on("click", removeCombatant); + + // add event listener to damage sliders in combatant modal + $("#combatant-modal-stun, #combatant-modal-physical").on("change", function() { + if ($("#combatant-modal-stun").val() == "10" || $("#combatant-modal-physical").val() == "10") { + $("#combatant-modal-penalties").text("incapacitated"); + } else { + $("#combatant-modal-penalties").text("-" + DAMAGE_PENALTY[$("#combatant-modal-stun").val()] + " (stun) and -" + DAMAGE_PENALTY[$("#combatant-modal-physical").val()] + " (physical)"); + } + }); + // always focus name input field when combatant modal appears $('#combatant-modal').on('shown.bs.modal', function () { $('#combatant-modal-name').focus();