diff --git a/Pages/AdminPlants.php b/Pages/AdminPlants.php index 8f30636..2ffd345 100644 --- a/Pages/AdminPlants.php +++ b/Pages/AdminPlants.php @@ -48,6 +48,20 @@ $PageSection = "Admin"; > New plant + + + + + +
-

Permanent upgrades

- -

- Expand your active Garden, buy additional Gardens, - or unlock information and quality-of-life features. -

+

+ +

+ id="PermanentUpgradesContent" + class="ShopSectionContent" + hidden + > +

+ Expand your active Garden, buy additional Gardens, + or unlock information and quality-of-life features. +

+ +
+
-

Seeds

+

+ +

+ id="SeedsContent" + class="ShopSectionContent" + > +
+

diff --git a/Scripts/Garden/AdminPlantEditor.js b/Scripts/Garden/AdminPlantEditor.js index dff8862..8489604 100644 --- a/Scripts/Garden/AdminPlantEditor.js +++ b/Scripts/Garden/AdminPlantEditor.js @@ -64,6 +64,13 @@ function BindAdminPlantEditor() { StartNewAdminPlant ); + document.getElementById( + "AdminPlantDuplicateButton" + ).addEventListener( + "click", + DuplicateAdminPlant + ); + document.getElementById( "AdminPlantForm" ).addEventListener( @@ -279,6 +286,7 @@ async function LoadAdminPlants( AdminPlantMutationCatalogue; RenderAdminPlantSelect(); + RenderAdminPlantDuplicateSelect(); const Keys = GetSortedAdminPlantKeys(); @@ -376,6 +384,70 @@ function RenderAdminPlantSelect() { } +function RenderAdminPlantDuplicateSelect() { + const Select = + document.getElementById( + "AdminPlantDuplicateSelect" + ); + + if (Select === null) { + return; + } + + const PreviousValue = + Select.value; + + Select.replaceChildren(); + + for ( + const PlantKey + of GetSortedAdminPlantKeys() + ) { + const Plant = + AdminPlantCatalogue[ + PlantKey + ]; + + const Option = + document.createElement( + "option" + ); + + Option.value = + PlantKey; + + Option.textContent = + String( + Plant.Id + ).padStart( + 3, + "0" + ) + + " — " + + Plant.Name + + ( + Plant.Archived === true + ? " (archived)" + : "" + ); + + Select.appendChild( + Option + ); + } + + if ( + PreviousValue !== "" && + AdminPlantCatalogue[ + PreviousValue + ] !== undefined + ) { + Select.value = + PreviousValue; + } +} + + function LoadAdminPlantIntoForm( PlantKey ) { @@ -475,6 +547,123 @@ function LoadAdminPlantIntoForm( } +function DuplicateAdminPlant() { + const SourcePlantKey = + document.getElementById( + "AdminPlantDuplicateSelect" + ).value; + + const SourcePlant = + AdminPlantCatalogue[ + SourcePlantKey + ]; + + if (SourcePlant === undefined) { + SetAdminPlantMessage( + "Choose a plant to duplicate." + ); + + return; + } + + AdminPlantEditingKey = null; + + document.getElementById( + "AdminPlantSelect" + ).value = ""; + + SetAdminPlantField( + "AdminPlantId", + GetNextAdminPlantId() + ); + + SetAdminPlantField( + "AdminPlantKey", + "" + ); + + SetAdminPlantField( + "AdminPlantName", + "" + ); + + SetAdminPlantField( + "AdminPlantDescription", + SourcePlant.Description ?? "" + ); + + SetAdminPlantField( + "AdminPlantTags", + Array.isArray( + SourcePlant.Tags + ) + ? SourcePlant.Tags.join( + ", " + ) + : "" + ); + + SetAdminPlantDurationFields( + Number( + SourcePlant.GrowthTime ?? + 0 + ) + ); + + SetAdminPlantField( + "AdminPlantHarvestMultiplier", + Number( + SourcePlant.HarvestMultiplier ?? + 1.5 + ) + ); + + document.getElementById( + "AdminPlantShopPlant" + ).checked = + SourcePlant.Shop?.ShopPlant === true; + + SetAdminPlantField( + "AdminPlantBaseCost", + SourcePlant.Shop?.BaseCost ?? "" + ); + + SetAdminPlantField( + "AdminPlantEffects", + JSON.stringify( + SourcePlant.Effects ?? {}, + null, + 4 + ) + ); + + document.getElementById( + "AdminPlantId" + ).readOnly = false; + + document.getElementById( + "AdminPlantKey" + ).readOnly = false; + + document.getElementById( + "AdminPlantArchiveNote" + ).hidden = true; + + UpdateAdminPlantShopFields(); + RenderAdminPlantPreview(); + + document.getElementById( + "AdminPlantName" + ).focus(); + + SetAdminPlantMessage( + "Duplicated " + + SourcePlant.Name + + ". Give the new plant a name and Plant Key before saving. Sprites are not copied." + ); +} + + function StartNewAdminPlant() { AdminPlantEditingKey = null; diff --git a/Scripts/Garden/Shop.js b/Scripts/Garden/Shop.js index 40c2fe1..af7e673 100644 --- a/Scripts/Garden/Shop.js +++ b/Scripts/Garden/Shop.js @@ -21,10 +21,69 @@ async function StartShop() { ShopSave = await LoadGame(); + BindShopSectionToggles(); RenderShop(); } +function BindShopSectionToggles() { + BindShopSectionToggle( + "PermanentUpgradesToggle", + "PermanentUpgradesContent" + ); + + BindShopSectionToggle( + "SeedsToggle", + "SeedsContent" + ); +} + + +function BindShopSectionToggle( + ToggleId, + ContentId +) { + const Toggle = + document.getElementById( + ToggleId + ); + + const Content = + document.getElementById( + ContentId + ); + + if ( + Toggle === null || + Content === null + ) { + return; + } + + Toggle.addEventListener( + "click", + () => { + const IsExpanded = + Toggle.getAttribute( + "aria-expanded" + ) === "true"; + + const NewExpanded = + !IsExpanded; + + Toggle.setAttribute( + "aria-expanded", + String(NewExpanded) + ); + + Content.hidden = + !NewExpanded; + + } + ); +} + + function RenderShop() { RenderShopCurrency(); RenderShopSeeds(); @@ -413,7 +472,12 @@ function CreatePlantInformationUpgradeCard() { ); Header.className = - "ShopItemHeader"; + "ShopItemHeader" + + ( + IsOwned + ? " ShopItemHeaderOwned" + : "" + ); const Name = @@ -529,7 +593,12 @@ function CreateGardenOverviewUpgradeCard() { ); Header.className = - "ShopItemHeader"; + "ShopItemHeader" + + ( + IsOwned + ? " ShopItemHeaderOwned" + : "" + ); const Name = @@ -645,7 +714,12 @@ function CreateGardenEconomyUpgradeCard() { ); Header.className = - "ShopItemHeader"; + "ShopItemHeader" + + ( + IsOwned + ? " ShopItemHeaderOwned" + : "" + ); const Name = @@ -759,7 +833,12 @@ function CreateMutationHintsUpgradeCard() { ); Header.className = - "ShopItemHeader"; + "ShopItemHeader" + + ( + IsOwned + ? " ShopItemHeaderOwned" + : "" + ); const Name = diff --git a/Styles/Style.css b/Styles/Style.css index 9c7a2ad..8424134 100644 --- a/Styles/Style.css +++ b/Styles/Style.css @@ -1126,6 +1126,48 @@ input, button, textarea, select { margin-top: 1.5rem; } +.ShopSectionHeading { + margin-bottom: 0.75rem; +} + +.ShopSectionToggle { + display: flex; + width: 100%; + gap: 0.55rem; + align-items: center; + padding: 0; + cursor: pointer; + color: var(--Text); + background: none; + border: 0; + font-size: inherit; + text-align: left; +} + +.ShopSectionToggle:hover { + color: var(--Sky); +} + +.ShopSectionToggle:focus-visible { + outline: 3px solid var(--Yellow); + outline-offset: 3px; +} + +.ShopSectionArrow { + width: 1ch; + flex: 0 0 1ch; + color: var(--Overlay2); + transform-origin: center; +} + +.ShopSectionToggle[aria-expanded="true"] .ShopSectionArrow { + transform: rotate(90deg); +} + +.ShopSectionContent[hidden] { + display: none; +} + .ShopSeedList { display: grid; grid-template-columns: repeat( auto-fit, minmax(15rem, 1fr) ); @@ -1153,6 +1195,11 @@ input, button, textarea, select { margin: 0; } +.ShopItemHeaderOwned { + color: var(--Overlay1); + border-bottom-color: var(--Surface1); +} + .ShopItemBody { display: grid; grid-template-columns: 5.75rem minmax(0, 1fr);