diff --git a/css/gui/tabs.css b/css/gui/tabs.css index 2e52d21325ebb9c4ad8fd49562e1e56c010b9986..afa0a58b8123c4d52780f7985b9d774656867b74 100644 --- a/css/gui/tabs.css +++ b/css/gui/tabs.css @@ -52,8 +52,16 @@ div.tab-bar a.active { cursor: default; } -.tab-content:not(.noFade) { +.tab-content { display: none; +} + +.tab-content.active { + display: unset; +} + +.tab-content:not(.noFade) { + /*display: none;*/ padding: 6px 12px; -webkit-animation: fadeEffect 0.3s; animation: fadeEffect 0.3s; diff --git a/src/002-config/mousetrapConfig.js b/src/002-config/mousetrapConfig.js index dd39ff0c3d8b77d5ca4062e99907c29746b1c5b6..db63020ef25ca8bf526d27db67d23a91c7f93db6 100644 --- a/src/002-config/mousetrapConfig.js +++ b/src/002-config/mousetrapConfig.js @@ -328,12 +328,18 @@ App.UI.Hotkeys.add("next-child", { }); App.UI.Hotkeys.add("Previous Tab", { callback: function() { + // Basically telling two different systems to go to the left tab, but since we never have multiple tab bars on + // the same page (as that is bad UI design) the player won't notice. App.UI.tabBar.openLeftTab(); + App.UI.tabs.left(); }, combinations: [] }); App.UI.Hotkeys.add("Next Tab", { callback: function() { + // Basically telling two different systems to go to the right tab, but since we never have multiple tab bars on + // the same page (as that is bad UI design) the player won't notice. App.UI.tabBar.openRightTab(); + App.UI.tabs.right(); }, combinations: [] }); App.UI.Hotkeys.add("walkpast", { diff --git a/src/gui/tabs.js b/src/gui/tabs.js new file mode 100644 index 0000000000000000000000000000000000000000..da794affab02357140d3f2de3e3219791a58ff5a --- /dev/null +++ b/src/gui/tabs.js @@ -0,0 +1,135 @@ +App.UI.tabs = (function() { + /** + * @type {Array<HTMLButtonElement>} + */ + let active = null; + + class TabBar { + /** + * @typedef tab + * @property {string} name + * @property {string} id + * @property {Node} content + * @property {string} [buttonClass] + */ + + /** + * @param {string} id Saved, should stay the same across versions. No spaces allowed + */ + constructor(id) { + this._id = id; + /** + * @type {Array<tab>} + */ + this._tabs = []; + } + + /** + * @param {string} name Display name + * @param {string} id Saved, should stay the same across versions + * @param {Node} content + * @param {string} [buttonClass] class applied to the button + */ + addTab(name, id, content, buttonClass) { + this._tabs.push({ + name: name, + id: id, + content: content, + buttonClass: buttonClass, + }); + } + + /** + * @returns {DocumentFragment} + */ + render() { + const f = new DocumentFragment(); + const tabBar = document.createElement("div"); + tabBar.classList.add("tab-bar"); + f.append(tabBar); + + /** + * @type {Array<HTMLButtonElement>} + */ + const buttonList = []; + /** + * @type {Array<HTMLDivElement>} + */ + const contentList = []; + + let selected = true; + for (const tab of this._tabs) { + // check if selected. If this tab bar has no entry yet the first tab will be true and all other false. + if (V.tabChoice.hasOwnProperty(this._id)) { + selected = V.tabChoice[this._id] === tab.id; + } + + const button = App.UI.DOM.appendNewElement("button", tabBar, tab.name, tab.buttonClass); + buttonList.push(button); + const contentHolder = App.UI.DOM.appendNewElement("div", f, tab.content, "tab-content"); + contentList.push(contentHolder); + + button.onclick = () => { + buttonList.forEach(c => { c.classList.remove("active"); }); + contentList.forEach(c => { c.classList.remove("active"); }); + button.classList.add("active"); + contentHolder.classList.add("active"); + }; + + if (selected) { + contentHolder.classList.add("active"); + button.classList.add("active"); + } + + selected = false; + } + + active = buttonList; + + return f; + } + } + + /** + * Call on passageinit to clear the button/content cache. + * Shouldn't matter, but we don't need to have huge DOM trees floating around. + */ + function clear() { + active = null; + } + + function openLeft() { + if (active) { + const index = currentIndex(); + if (index - 1 >= 0) { + active[index - 1].click(); + } + } + } + + function openRight() { + if (active) { + const index = currentIndex(); + if (index > -1 && index + 1 < active.length) { + active[index + 1].click(); + } + } + } + + function currentIndex() { + for (let i = 0; i < active.length; i++) { + if (active[i].classList.contains("active")) { + return i; + } + } + return -1; + } + + return { + TabBar: TabBar, + clear: clear, + left: openLeft, + right: openRight + }; +})(); + diff --git a/src/npc/startingGirls/startingGirlsPassage.js b/src/npc/startingGirls/startingGirlsPassage.js index 7f6b689fed0adbdb35c0e752a1305b1edfee46a8..528e098f34e5ad1e20b6d89a35a36c174e04cf1e 100644 --- a/src/npc/startingGirls/startingGirlsPassage.js +++ b/src/npc/startingGirls/startingGirlsPassage.js @@ -397,60 +397,20 @@ App.StartingGirls.passage = function() { App.UI.DOM.appendNewElement("h2", el, "You are customizing this slave:"); el.append(App.Desc.longSlave(V.activeSlave, {market: "generic"})); - // TODO: move me - /** - * - * @param {string} id - * @param {Node} element - * @returns {HTMLSpanElement} - */ - function makeSpanIded(id, element) { - const span = document.createElement("span"); - span.id = id; - span.append(element); - return span; - } - - const tabCaptions = { - "profile": 'Profile', - "physical": 'Physical', - "upper": 'Upper', - "lower": 'Lower', - "mental": 'Mental', - "skills": 'Skills', - "stats": 'Stats', - "family": 'Family', - "bodyMods": 'Body Mods', - "salon": 'Salon', - "finalize": 'Finalize', - }; - - const tabBar = App.UI.DOM.appendNewElement("div", el, '', "tab-bar"); - tabBar.append( - App.UI.tabBar.tabButton('profile', tabCaptions.profile), - App.UI.tabBar.tabButton('physical', tabCaptions.physical), - App.UI.tabBar.tabButton('upper', tabCaptions.upper), - App.UI.tabBar.tabButton('lower', tabCaptions.lower), - App.UI.tabBar.tabButton('mental', tabCaptions.mental), - App.UI.tabBar.tabButton('skills', tabCaptions.skills), - App.UI.tabBar.tabButton('stats', tabCaptions.stats), - App.UI.tabBar.tabButton('family', tabCaptions.family), - App.UI.tabBar.tabButton('body-mods', tabCaptions.bodyMods), - App.UI.tabBar.tabButton('salon', tabCaptions.salon), - App.UI.tabBar.tabButton('finalize', tabCaptions.finalize), - ); - - el.append(App.UI.tabBar.makeTab('profile', makeSpanIded("content-profile", App.StartingGirls.profile(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('physical', makeSpanIded("content-physical", App.StartingGirls.physical(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('upper', makeSpanIded("content-upper", App.StartingGirls.upper(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('lower', makeSpanIded("content-lower", App.StartingGirls.lower(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('mental', makeSpanIded("content-mental", App.StartingGirls.mental(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('skills', makeSpanIded("content-skills", App.StartingGirls.skills(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('stats', makeSpanIded("content-stats", App.StartingGirls.stats(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('family', makeSpanIded("content-family", App.Intro.editFamily(V.activeSlave)))); - el.append(App.UI.tabBar.makeTab('body-mods', makeSpanIded("content-body-mods", App.UI.bodyModification(V.activeSlave, true)))); - el.append(App.UI.tabBar.makeTab('salon', makeSpanIded("content-salon", App.UI.salon(V.activeSlave, true)))); - el.append(App.UI.tabBar.makeTab('finalize', makeSpanIded("content-finalize", App.StartingGirls.finalize(V.activeSlave)))); + const tabBar = new App.UI.tabs.TabBar("StartingGirls"); + tabBar.addTab("Profile", "profile", App.StartingGirls.profile(V.activeSlave)); + tabBar.addTab("Physical", "physical", App.StartingGirls.physical(V.activeSlave)); + tabBar.addTab("Upper", "upper", App.StartingGirls.upper(V.activeSlave)); + tabBar.addTab("Lower", "lower", App.StartingGirls.lower(V.activeSlave)); + tabBar.addTab("Mental", "mental", App.StartingGirls.mental(V.activeSlave)); + tabBar.addTab("Skills", "skills", App.StartingGirls.skills(V.activeSlave)); + tabBar.addTab("Stats", "stats", App.StartingGirls.stats(V.activeSlave)); + tabBar.addTab("Family", "family", App.Intro.editFamily(V.activeSlave)); + tabBar.addTab("Body Mods", "body-mods", App.UI.bodyModification(V.activeSlave, true)); + tabBar.addTab("Salon", "salon", App.UI.salon(V.activeSlave, true)); + tabBar.addTab("Finalize", "finalize", App.StartingGirls.finalize(V.activeSlave), + startingSlaveCost(V.activeSlave) > V.cash ? "show-warning" : undefined); + el.append(tabBar.render()); return el; }; diff --git a/src/zz1-last/setupEventHandlers.js b/src/zz1-last/setupEventHandlers.js index 8ad72f2310c94cbd84210b3e47fc61fb59283a27..9cda9e368e9b93dfee0fc1d1886d96f9e00e418b 100644 --- a/src/zz1-last/setupEventHandlers.js +++ b/src/zz1-last/setupEventHandlers.js @@ -13,6 +13,7 @@ $(document).on(":passageinit", () => { V.passageSwitchHandler(); delete V.passageSwitchHandler; } + App.UI.tabs.clear(); profileEvents.passageinit(); });