From 4bc6f6a3ee904a47769ab19c819345bc948876e0 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Thu, 22 Feb 2024 17:26:07 +0800 Subject: [PATCH 01/15] Prototype search bar for the backlog Signed-off-by: Egor Savkin --- static/js/shop/Backlog.jsx | 44 ++++++-------------------- static/js/shop/BacklogGroups.jsx | 44 ++++++++++++++++++++++++++ static/js/shop/BacklogSearchResult.jsx | 16 ++++++++++ static/js/shop/SearchBar.jsx | 19 +++++++++++ static/js/shop/shop_store.js | 16 ++++++++++ 5 files changed, 104 insertions(+), 35 deletions(-) create mode 100644 static/js/shop/BacklogGroups.jsx create mode 100644 static/js/shop/BacklogSearchResult.jsx create mode 100644 static/js/shop/SearchBar.jsx diff --git a/static/js/shop/Backlog.jsx b/static/js/shop/Backlog.jsx index 2b14ff7..feba9ba 100644 --- a/static/js/shop/Backlog.jsx +++ b/static/js/shop/Backlog.jsx @@ -1,9 +1,11 @@ import React from 'react'; import {Droppable} from "@hello-pangea/dnd"; -import {ProductItem} from "./ProductItem"; import {useShopStore} from "./shop_store"; // #!render_count import {useRenderCount} from "@uidotdev/usehooks"; +import {BacklogGroups} from "./BacklogGroups"; +import {SearchBar} from "./SearchBar"; +import {BacklogSearchResult} from "./BacklogSearchResult"; /** * Component that renders the backlog in the aside @@ -14,43 +16,13 @@ export function Backlog() { const data = useShopStore((state) => state.groups); const items = useShopStore((state) => state.cards); + const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu); const isMobile = useShopStore((state) => state.isMobile); // #!render_count console.log("Backlog renders: ", renderCount) - const ordered_groups = data.categories.map(groupItem => ({ - name: groupItem.name, - items: groupItem.itemIds.map(itemId => items[itemId]) - })); - let item_index = -1; - const groups = ordered_groups.map((group, g_index) => { - return ( -
-

- -

-
-
- {group.items.map(item => { - item_index++; - return ( - - ) - })} -
-
-
- ); - } - ); - return ( ) : null} -
- {groups} -
+ + + + + {provided.placeholder && (
diff --git a/static/js/shop/BacklogGroups.jsx b/static/js/shop/BacklogGroups.jsx new file mode 100644 index 0000000..592d68e --- /dev/null +++ b/static/js/shop/BacklogGroups.jsx @@ -0,0 +1,44 @@ +import {ProductItem} from "./ProductItem"; +import React from "react"; +import {useShopStore} from "./shop_store"; + +export function BacklogGroups() { + const data = useShopStore((state) => state.groups); + const items = useShopStore((state) => state.cards); + + const ordered_groups = data.categories.map(groupItem => ({ + name: groupItem.name, + items: groupItem.itemIds.map(itemId => items[itemId]) + })); + let item_index = -1; + const groups = ordered_groups.map((group, g_index) => { + return ( +
+

+ +

+
+
+ {group.items.map(item => { + item_index++; + return ( + + ) + })} +
+
+
+ ); + } + ); + return ( +
+ {groups} +
+ ) +} \ No newline at end of file diff --git a/static/js/shop/BacklogSearchResult.jsx b/static/js/shop/BacklogSearchResult.jsx new file mode 100644 index 0000000..77b4dd0 --- /dev/null +++ b/static/js/shop/BacklogSearchResult.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import {useShopStore} from "./shop_store"; +import {ProductItem} from "./ProductItem"; + + +export function BacklogSearchResult() { + const cards_to_display = useShopStore((state) => state.listed_cards); + return ( <> + {cards_to_display.map((item, _) => { + return ( + + ) + })} + + ) +} \ No newline at end of file diff --git a/static/js/shop/SearchBar.jsx b/static/js/shop/SearchBar.jsx new file mode 100644 index 0000000..7285a0e --- /dev/null +++ b/static/js/shop/SearchBar.jsx @@ -0,0 +1,19 @@ +import React from 'react'; +import {useShopStore} from "./shop_store"; + +export function SearchBar() { + const search_bar_value = useShopStore((state) => state.search_bar_value); + const updateSearchBar = useShopStore((state) => state.updateSearchBar); + + return ( +
+ updateSearchBar(event.target.value)} + aria-label="Search"/> +
+ ) +} \ No newline at end of file diff --git a/static/js/shop/shop_store.js b/static/js/shop/shop_store.js index 05c5e28..b98d3a1 100644 --- a/static/js/shop/shop_store.js +++ b/static/js/shop/shop_store.js @@ -29,6 +29,21 @@ const useBacklog = ((set, get) => ({ cardIndexById: card_id => get().cards_list.findIndex((element) => (card_id === element)) })); +const useSearch = ((set, get) => ({ + search_index: Array.from(Object.values(shared_data.items) + .map((card, _) => ( + [(card.name + " " + card.name_number + " " + card.name_codename).toLowerCase(), card.id] + ))), + search_bar_value: "", + listed_cards: [], + updateSearchBar: text => set(state => ({ + search_bar_value: text, + listed_cards: text.length > 0 ? Array.from(get().search_index + .filter((card, _) => card[0].includes(text.toLowerCase())) + .map(([index, card_id], _) => get().cards_list.findIndex(elem => elem === card_id))) : [] + })) +})); + const useCrateModes = ((set, get) => ({ crate_modes: shared_data.crateModes, modes_order: shared_data.crateModeOrder, @@ -569,6 +584,7 @@ const useCart = ((set, get) => ({ export const useShopStore = createWithEqualityFn((...params) => ({ ...useBacklog(...params), + ...useSearch(...params), ...useCrateModes(...params), ...useCart(...params), ...useSubmitForm(...params), -- 2.44.1 From aa353482885aefdc95a829426e55dbddf45c31d7 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 23 Feb 2024 15:28:39 +0800 Subject: [PATCH 02/15] Apply styles to the search bar Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 41 ++++++++++++++++++++++++++++++ static/images/shop/icon-search.svg | 39 ++++++++++++++++++++++++++++ static/js/shop/Backlog.jsx | 22 ++++++++++------ static/js/shop/SearchBar.jsx | 5 ++-- 4 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 static/images/shop/icon-search.svg diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index be2a8fe..1e066d6 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -178,6 +178,47 @@ button { .backlog-container { padding-bottom: 4rem; + + .backlog-bar { + display: flex; + width: 100%; + margin: 0.4rem 0; + padding: 0 0.5rem; + justify-content: space-around; + + .mobileCloseMenu { + display: flex; + padding: 0; + margin: 0; + width: 10%; + align-content: center; + } + .search-backlog { + display: inline-block; + border: 0; + width: 90%; + + .search-backlog-input { + display: inline; + border: 0; + color: white; + border-radius: 2rem; + background: rgba(255, 255, 255, 0.15) url("/images/shop/icon-search.svg") no-repeat; + background-position: right 2% center; + background-size: 20px; + padding-right: 1rem; + + &::placeholder { + color: white; + opacity: 0.5; + } + + &:focus { + box-shadow: none; + } + } + } + } } .rule { diff --git a/static/images/shop/icon-search.svg b/static/images/shop/icon-search.svg new file mode 100644 index 0000000..232e21e --- /dev/null +++ b/static/images/shop/icon-search.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/static/js/shop/Backlog.jsx b/static/js/shop/Backlog.jsx index feba9ba..67b4bf4 100644 --- a/static/js/shop/Backlog.jsx +++ b/static/js/shop/Backlog.jsx @@ -34,15 +34,21 @@ export function Backlog() { ref={provided.innerRef} {...provided.droppableProps}> - {isMobile ? ( -
- -
- ) : null} - + +
+ + + {isMobile ? ( +
+ +
+ ) : null} +
+ + diff --git a/static/js/shop/SearchBar.jsx b/static/js/shop/SearchBar.jsx index 7285a0e..7eceb60 100644 --- a/static/js/shop/SearchBar.jsx +++ b/static/js/shop/SearchBar.jsx @@ -4,12 +4,11 @@ import {useShopStore} from "./shop_store"; export function SearchBar() { const search_bar_value = useShopStore((state) => state.search_bar_value); const updateSearchBar = useShopStore((state) => state.updateSearchBar); - return ( -
+
updateSearchBar(event.target.value)} -- 2.44.1 From 56a44ce4a3fd66d989aef09203ec0f0bc330cd60 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 23 Feb 2024 17:28:28 +0800 Subject: [PATCH 03/15] Do not show groups when there are search results Signed-off-by: Egor Savkin --- static/js/shop/Backlog.jsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/static/js/shop/Backlog.jsx b/static/js/shop/Backlog.jsx index 67b4bf4..f1b6874 100644 --- a/static/js/shop/Backlog.jsx +++ b/static/js/shop/Backlog.jsx @@ -19,6 +19,7 @@ export function Backlog() { const onClickToggleMobileSideMenu = useShopStore((state) => state.switchSideMenu); const isMobile = useShopStore((state) => state.isMobile); + const showSearch = useShopStore((state) => state.listed_cards.length > 0); // #!render_count console.log("Backlog renders: ", renderCount) @@ -48,11 +49,7 @@ export function Backlog() { ) : null}
- - - - - + {showSearch ? : } {provided.placeholder && (
-- 2.44.1 From eb196b086e54a395f65832213a57d0eaba53a95f Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Mon, 26 Feb 2024 17:36:15 +0800 Subject: [PATCH 04/15] Make fonts sizes more consistent and fiz minor paddings issues Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 13 +++- static/css/order-hardware.css | 66 +++++++++++--------- static/js/shop/SummaryCrateCard.jsx | 6 +- static/js/shop/SummaryCratePricedOptions.jsx | 5 +- 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index 1e066d6..d4330b3 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -72,6 +72,8 @@ button { overflow-y: scroll; overflow-x: hidden; position: relative; + max-width: calc(3/10 * 100%); + min-width: calc(1/4 * 100%); /*padding-bottom: 4rem!important;*/ } @@ -79,7 +81,8 @@ button { position: fixed; bottom: 0; height: 100px; - width: calc(2 / 6 * 100%); + max-width: calc(3/10 * 100%); + min-width: 0; content: ""; background: linear-gradient( to top, @@ -91,7 +94,7 @@ button { > section.main { flex: 4; - max-width: calc(4 / 6 * 100%); + max-width: calc(3/4 * 100%); overflow-y: scroll; } } @@ -100,7 +103,7 @@ button { display: flex; color: white; - padding: 3rem 2rem 1rem; + padding: 1rem 0rem 1rem 1.5rem; .content { flex: 1; @@ -119,6 +122,7 @@ button { h3 { color: white; + font-size: 1.5rem; } button { @@ -282,6 +286,9 @@ button { .item-card-name { font-weight: 700; + &.tabbed { + padding-left: 16px; + } } .price { diff --git a/static/css/order-hardware.css b/static/css/order-hardware.css index 3a009e7..550172e 100644 --- a/static/css/order-hardware.css +++ b/static/css/order-hardware.css @@ -55,7 +55,7 @@ color: white; font-weight: bold; font-size: 1.75rem; - padding: .75rem 2rem; + padding: .75rem 1.5rem; } #accordion_categories .accordion-body { @@ -94,6 +94,10 @@ height: calc(100vh - 10px - 2.5rem); /* .navbar vertical padding + line height (.navbar-brand.font-size.rem * body.font-size * body.line-height)*/ } + #root-shop .layout>aside.aside { + min-width: max(300px, 30%); + } + #root-shop .productItem { padding: 2rem 1rem 1rem; } @@ -111,7 +115,7 @@ } #root-shop .productItem .content ul { - font-size: .6rem; + font-size: .75rem; } #root-shop .panel .control { @@ -133,7 +137,7 @@ } #root-shop .panel .summary>.summary-price table { - font-size: 1rem; + font-size: 0.8rem; } #root-shop .panel .summary>.summary-form form, @@ -163,7 +167,7 @@ } #root-shop table tr { - padding: .8em 0; + padding: .2em 0; display: flex !important; justify-content: space-between; } @@ -192,7 +196,7 @@ } body { - font-size: .7rem; + font-size: .8rem; } #root-shop, #root-shop>div { @@ -217,7 +221,7 @@ } #root-shop table tr { - padding: .8em 0; + padding: .2em 0; display: flex !important; justify-content: space-between; } @@ -227,7 +231,7 @@ } #root-shop .panel .summary>.summary-price table { - font-size: .7rem; + font-size: .8rem; } #root-shop .panel .summary>.summary-form form, @@ -236,7 +240,7 @@ } #root-shop .panel .summary>.summary-price tfoot { - font-size: .85rem; + font-size: 1.0rem; } /*#root-shop .panel .summary>.summary-form form input[type="submit"] { @@ -288,7 +292,7 @@ } body { - font-size: .7rem; + font-size: .8rem; } #root-shop, #root-shop>div { @@ -308,11 +312,11 @@ } #root-shop .productItem .content h3 { - font-size: 1rem; + font-size: 1.25rem; } #root-shop .productItem .content ul { - font-size: .5rem; + font-size: .75rem; } #root-shop .panel { @@ -345,7 +349,7 @@ } #root-shop .panel .summary>.summary-price table { - font-size: .7rem; + font-size: .8rem; } #root-shop .panel .summary>.summary-form form, @@ -354,7 +358,7 @@ } #root-shop .panel .summary>.summary-price tfoot { - font-size: .85rem; + font-size: 1rem; } /*#root-shop .panel .summary>.summary-form form input[type="submit"] { @@ -367,7 +371,6 @@ border-top-right-radius: 30px; width: 80px; padding: 5px 0 5px 10px; - margin-bottom: -25px; margin-left: -1.3rem; position: relative; z-index: 1; @@ -386,7 +389,7 @@ } #root-shop table tr { - padding: .8em 0; + padding: .2em 0; display: flex !important; justify-content: space-between; } @@ -394,14 +397,15 @@ #root-shop .layout>aside.aside.menu-opened { /*transform: translate3d(0, 0, 0);*/ transition: left .3s; - width: 310px; + width: min(310px, 60vw); + max-width: 60%; left: 0; } #root-shop .layout>aside.aside.menu-opened + section.main { /*transform: translate3d(310px, 0, 0);*/ transition: left .3s; - left: 310px; + left: min(310px, 60vw); position: relative; z-index: 0; } @@ -422,8 +426,8 @@ transition: left .3s; position: fixed; z-index: 1; - left: -310px; - width: 310px; + left: max(-310px, -60vw); + width: min(310px, 60vw); height: 100%; } @@ -460,7 +464,7 @@ } #accordion_categories button { - font-size: 1rem; + font-size: 1.5rem; padding: .5rem 0.5rem; } } @@ -500,7 +504,7 @@ } body { - font-size: .7rem; + font-size: .8rem; } #root-shop, #root-shop>div { @@ -516,20 +520,21 @@ } #root-shop .productItem .content h3 { - font-size: 1rem; + font-size: 1.25rem; } #root-shop .layout>aside.aside.menu-opened { /*transform: translate3d(0, 0, 0);*/ transition: left .3s; - width: 310px; + width: min(310px, 90vw); + max-width: 90%; left: 0; } #root-shop .layout>aside.aside.menu-opened + section.main { /*transform: translate3d(310px, 0, 0);*/ transition: left .3s; - left: 310px; + left: min(310px, 90vw); position: relative; z-index: 0; } @@ -549,8 +554,8 @@ transition: left .3s; position: fixed; z-index: 1; - left: -310px; - width: 310px; + left: max(-310px, -90vw); + width: min(310px, 90vw); height: 100%; } @@ -611,7 +616,7 @@ } #root-shop .panel .summary>.summary-price table { - font-size: .7rem; + font-size: .8rem; } #root-shop .panel .summary>.summary-form form, @@ -620,7 +625,7 @@ } #root-shop .panel .summary>.summary-price tfoot { - font-size: .85rem; + font-size: 1rem; } /*#root-shop .panel .summary>.summary-form form input[type="submit"] { @@ -633,7 +638,6 @@ border-top-right-radius: 30px; width: 80px; padding: 5px 0 5px 10px; - margin-bottom: 15px; margin-left: -1.3rem; } @@ -650,7 +654,7 @@ } #root-shop table tr { - padding: .8em 0; + padding: .2em 0; display: flex !important; justify-content: space-between; } @@ -669,7 +673,7 @@ } #accordion_categories button { - font-size: 1rem; + font-size: 1.5rem; padding: .5rem 0.5rem; } } \ No newline at end of file diff --git a/static/js/shop/SummaryCrateCard.jsx b/static/js/shop/SummaryCrateCard.jsx index 81018db..3edc55d 100644 --- a/static/js/shop/SummaryCrateCard.jsx +++ b/static/js/shop/SummaryCrateCard.jsx @@ -41,11 +41,7 @@ export function SummaryCrateCard({crate_index, card_index}) { onClick={() => setHighlight(crate_id, card_index)} onMouseEnter={() => setHighlight(crate_id, card_index)} onMouseLeave={() => resetHighlight()}> - -   +
{`${card.name_number} ${card.name} ${card.name_codename}`}
diff --git a/static/js/shop/SummaryCratePricedOptions.jsx b/static/js/shop/SummaryCratePricedOptions.jsx index 18ae07a..6cc894b 100644 --- a/static/js/shop/SummaryCratePricedOptions.jsx +++ b/static/js/shop/SummaryCratePricedOptions.jsx @@ -23,10 +23,7 @@ export function SummaryCratePricedOptions({crate_index}) { return options.map((option, _i) => ( - -   +
{option.title}
-- 2.44.1 From 1cb9c90c65f4fb6e4a3b7f4d038e59f7721ec1a4 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Tue, 27 Feb 2024 17:23:05 +0800 Subject: [PATCH 05/15] Fix bottom side gradient Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 33 +++++++++++++++---------------- static/css/order-hardware.css | 14 ++++++++----- static/js/shop.bundle.js | 2 +- static/js/shop/Backlog.jsx | 3 +++ static/js/shop/GradientBottom.jsx | 7 +++++++ 5 files changed, 36 insertions(+), 23 deletions(-) create mode 100644 static/js/shop/GradientBottom.jsx diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index d4330b3..599d048 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -72,29 +72,28 @@ button { overflow-y: scroll; overflow-x: hidden; position: relative; - max-width: calc(3/10 * 100%); - min-width: calc(1/4 * 100%); + max-width: max(1/4 * 100%, 310px); /*padding-bottom: 4rem!important;*/ - } - > aside.aside:after { - position: fixed; - bottom: 0; - height: 100px; - max-width: calc(3/10 * 100%); - min-width: 0; - content: ""; - background: linear-gradient( - to top, - rgba(13, 53, 71, 1), - rgba(13, 53, 71, 0) - ); - pointer-events: none; + .gradient-bottom { + position: sticky; + bottom: 0; + height: 100px; + //width: max(1/4 * 100%, 310px); + width: inherit; + content: ""; + background: linear-gradient( + to top, + rgba(13, 53, 71, 1), + rgba(13, 53, 71, 0) + ); + pointer-events: none; + } } > section.main { flex: 4; - max-width: calc(3/4 * 100%); + width: calc(3/4 * 100%); overflow-y: scroll; } } diff --git a/static/css/order-hardware.css b/static/css/order-hardware.css index 550172e..5e6c6b0 100644 --- a/static/css/order-hardware.css +++ b/static/css/order-hardware.css @@ -98,6 +98,10 @@ min-width: max(300px, 30%); } + #root-shop .layout>aside.aside .gradient-bottom { + width: inherit; + } + #root-shop .productItem { padding: 2rem 1rem 1rem; } @@ -412,7 +416,7 @@ #root-shop .layout>aside.aside.menu-opened + section.main:after { content: ''; - position: absolute; + position: fixed; height: 100%; width: 100%; background-color: rgba(0, 0, 0, .3); @@ -431,8 +435,8 @@ height: 100%; } - #root-shop .layout>aside.aside:after { - width: 0; + #root-shop .layout>aside.aside .gradient-bottom { + display: none; } #root-shop .layout>aside.aside + section.main { @@ -559,8 +563,8 @@ height: 100%; } - #root-shop .layout>aside.aside:after { - width: 0; + #root-shop .layout>aside.aside .gradient-bottom { + display: none; } #root-shop .layout>aside.aside + section.main { diff --git a/static/js/shop.bundle.js b/static/js/shop.bundle.js index fb6502d..26f2e87 100644 --- a/static/js/shop.bundle.js +++ b/static/js/shop.bundle.js @@ -1,2 +1,2 @@ /*! For license information please see shop.bundle.js.LICENSE.txt */ -(()=>{var e={960:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),s=Symbol.for("react.context"),c=Symbol.for("react.server_context"),u=Symbol.for("react.forward_ref"),d=Symbol.for("react.suspense"),f=Symbol.for("react.suspense_list"),p=Symbol.for("react.memo"),m=Symbol.for("react.lazy");Symbol.for("react.offscreen");Symbol.for("react.module.reference"),t.isContextConsumer=function(e){return function(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case n:switch(e=e.type){case o:case i:case a:case d:case f:return e;default:switch(e=e&&e.$$typeof){case c:case s:case u:case m:case p:case l:return e;default:return t}}case r:return t}}}(e)===s}},896:(e,t,n)=>{"use strict";e.exports=n(960)},80:(e,t)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t{"use strict";var r=n(819),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||o}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var o=p(n);o&&o!==m&&e(t,o,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,o=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,f=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,y=n?Symbol.for("react.block"):60121,b=n?Symbol.for("react.fundamental"):60117,v=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function E(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case a:case l:case i:case p:return e;default:switch(e=e&&e.$$typeof){case c:case f:case h:case g:case s:return e;default:return t}}case o:return t}}}function x(e){return E(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=f,t.Fragment=a,t.Lazy=h,t.Memo=g,t.Portal=o,t.Profiler=l,t.StrictMode=i,t.Suspense=p,t.isAsyncMode=function(e){return x(e)||E(e)===u},t.isConcurrentMode=x,t.isContextConsumer=function(e){return E(e)===c},t.isContextProvider=function(e){return E(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return E(e)===f},t.isFragment=function(e){return E(e)===a},t.isLazy=function(e){return E(e)===h},t.isMemo=function(e){return E(e)===g},t.isPortal=function(e){return E(e)===o},t.isProfiler=function(e){return E(e)===l},t.isStrictMode=function(e){return E(e)===i},t.isSuspense=function(e){return E(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===d||e===l||e===i||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===s||e.$$typeof===c||e.$$typeof===f||e.$$typeof===b||e.$$typeof===v||e.$$typeof===w||e.$$typeof===y)},t.typeOf=E},819:(e,t,n)=>{"use strict";e.exports=n(560)},948:e=>{"use strict";e.exports=function(e,t,n,r,o,a,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,o,a,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},344:function(e,t,n){var r,o;r=function(){"use strict";Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)});var e={},t={"==":function(e,t){return e==t},"===":function(e,t){return e===t},"!=":function(e,t){return e!=t},"!==":function(e,t){return e!==t},">":function(e,t){return e>t},">=":function(e,t){return e>=t},"<":function(e,t,n){return void 0===n?e=t?[]:r}};return e.is_logic=function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&1===Object.keys(e).length},e.truthy=function(e){return!(Array.isArray(e)&&0===e.length||!e)},e.get_operator=function(e){return Object.keys(e)[0]},e.get_values=function(t){return t[e.get_operator(t)]},e.apply=function(n,r){if(Array.isArray(n))return n.map((function(t){return e.apply(t,r)}));if(!e.is_logic(n))return n;var o,a,i,l,s,c=e.get_operator(n),u=n[c];if(Array.isArray(u)||(u=[u]),"if"===c||"?:"==c){for(o=0;o0){var d=String(c).split("."),f=t;for(o=0;o{"use strict";var r=n(143);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},268:(e,t,n)=>{e.exports=n(776)()},143:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},516:(e,t,n)=>{"use strict";var r=n(504),o=n(712);function a(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n
)} + +
)} diff --git a/static/js/shop/GradientBottom.jsx b/static/js/shop/GradientBottom.jsx new file mode 100644 index 0000000..6c70fd6 --- /dev/null +++ b/static/js/shop/GradientBottom.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export function GradientBottom() { + return ( +
+ ) +} \ No newline at end of file -- 2.44.1 From 839d7c6612e791779864e32cf32dff7ed2332b48 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Wed, 28 Feb 2024 16:40:48 +0800 Subject: [PATCH 06/15] Fix search bar icon conflicting in webkit and make backlog scroll bar thin Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index 599d048..d2b96c8 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -73,6 +73,10 @@ button { overflow-x: hidden; position: relative; max-width: max(1/4 * 100%, 310px); + scrollbar-width: thin; + scrollbar-gutter: stable; + scrollbar-color: #6e7e87 transparent; + scrollbar-arrow-color: transparent; /*padding-bottom: 4rem!important;*/ .gradient-bottom { @@ -207,9 +211,10 @@ button { color: white; border-radius: 2rem; background: rgba(255, 255, 255, 0.15) url("/images/shop/icon-search.svg") no-repeat; - background-position: right 2% center; + background-position: left 2% center; background-size: 20px; padding-right: 1rem; + text-indent: 20px; &::placeholder { color: white; -- 2.44.1 From dfe1f0ea2d32bfed25d621d6d84c01e862f74352 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Fri, 15 Mar 2024 15:22:05 +0800 Subject: [PATCH 07/15] Rename backlog to catalog Signed-off-by: Egor Savkin --- sass/css/_shop.scss | 8 ++++---- static/css/order-hardware.css | 4 ++-- static/js/shop/{Backlog.jsx => Catalog.jsx} | 16 ++++++++-------- .../{BacklogGroups.jsx => CatalogGroups.jsx} | 2 +- ...gSearchResult.jsx => CatalogSearchResult.jsx} | 2 +- static/js/shop/ProductItem.jsx | 4 ++-- static/js/shop/SearchBar.jsx | 4 ++-- static/js/shop/Shop.jsx | 14 +++++++------- static/js/shop/shop_store.js | 12 ++++++------ static/js/shop/utils.js | 4 ++-- static/js/shop_data.js | 8 ++++---- 11 files changed, 39 insertions(+), 39 deletions(-) rename static/js/shop/{Backlog.jsx => Catalog.jsx} (81%) rename static/js/shop/{BacklogGroups.jsx => CatalogGroups.jsx} (98%) rename static/js/shop/{BacklogSearchResult.jsx => CatalogSearchResult.jsx} (91%) diff --git a/sass/css/_shop.scss b/sass/css/_shop.scss index d2b96c8..e6ca136 100644 --- a/sass/css/_shop.scss +++ b/sass/css/_shop.scss @@ -183,10 +183,10 @@ button { } } - .backlog-container { + .catalog-container { padding-bottom: 4rem; - .backlog-bar { + .catalog-bar { display: flex; width: 100%; margin: 0.4rem 0; @@ -200,12 +200,12 @@ button { width: 10%; align-content: center; } - .search-backlog { + .search-catalog { display: inline-block; border: 0; width: 90%; - .search-backlog-input { + .search-catalog-input { display: inline; border: 0; color: white; diff --git a/static/css/order-hardware.css b/static/css/order-hardware.css index 5e6c6b0..cc75723 100644 --- a/static/css/order-hardware.css +++ b/static/css/order-hardware.css @@ -458,7 +458,7 @@ overflow: initial; } - #root-shop .layout>aside.aside.menu-opened > .backlog-container { + #root-shop .layout>aside.aside.menu-opened > .catalog-container { overflow-y: scroll; height: 100%; } @@ -667,7 +667,7 @@ overflow: initial; } - #root-shop .layout>aside.aside.menu-opened > .backlog-container { + #root-shop .layout>aside.aside.menu-opened > .catalog-container { overflow-y: scroll; height: 100%; } diff --git a/static/js/shop/Backlog.jsx b/static/js/shop/Catalog.jsx similarity index 81% rename from static/js/shop/Backlog.jsx rename to static/js/shop/Catalog.jsx index e44427a..1f3e408 100644 --- a/static/js/shop/Backlog.jsx +++ b/static/js/shop/Catalog.jsx @@ -3,15 +3,15 @@ import {Droppable} from "@hello-pangea/dnd"; import {useShopStore} from "./shop_store"; // #!render_count import {useRenderCount} from "@uidotdev/usehooks"; -import {BacklogGroups} from "./BacklogGroups"; +import {CatalogGroups} from "./CatalogGroups"; import {SearchBar} from "./SearchBar"; -import {BacklogSearchResult} from "./BacklogSearchResult"; +import {CatalogSearchResult} from "./CatalogSearchResult"; import {GradientBottom} from "./GradientBottom"; /** - * Component that renders the backlog in the aside + * Component that renders the catalog in the aside */ -export function Backlog() { +export function Catalog() { // #!render_count const renderCount = useRenderCount(); @@ -23,7 +23,7 @@ export function Backlog() { const showSearch = useShopStore((state) => state.listed_cards.length > 0); // #!render_count - console.log("Backlog renders: ", renderCount) + console.log("Catalog renders: ", renderCount) return ( (
-
+
{isMobile ? ( @@ -50,7 +50,7 @@ export function Backlog() { ) : null}
- {showSearch ? : } + {showSearch ? : } {provided.placeholder && (
diff --git a/static/js/shop/BacklogGroups.jsx b/static/js/shop/CatalogGroups.jsx similarity index 98% rename from static/js/shop/BacklogGroups.jsx rename to static/js/shop/CatalogGroups.jsx index 592d68e..e4dc511 100644 --- a/static/js/shop/BacklogGroups.jsx +++ b/static/js/shop/CatalogGroups.jsx @@ -2,7 +2,7 @@ import {ProductItem} from "./ProductItem"; import React from "react"; import {useShopStore} from "./shop_store"; -export function BacklogGroups() { +export function CatalogGroups() { const data = useShopStore((state) => state.groups); const items = useShopStore((state) => state.cards); diff --git a/static/js/shop/BacklogSearchResult.jsx b/static/js/shop/CatalogSearchResult.jsx similarity index 91% rename from static/js/shop/BacklogSearchResult.jsx rename to static/js/shop/CatalogSearchResult.jsx index 77b4dd0..ae258dd 100644 --- a/static/js/shop/BacklogSearchResult.jsx +++ b/static/js/shop/CatalogSearchResult.jsx @@ -3,7 +3,7 @@ import {useShopStore} from "./shop_store"; import {ProductItem} from "./ProductItem"; -export function BacklogSearchResult() { +export function CatalogSearchResult() { const cards_to_display = useShopStore((state) => state.listed_cards); return ( <> {cards_to_display.map((item, _) => { diff --git a/static/js/shop/ProductItem.jsx b/static/js/shop/ProductItem.jsx index 9d5bf83..872fdb5 100644 --- a/static/js/shop/ProductItem.jsx +++ b/static/js/shop/ProductItem.jsx @@ -8,7 +8,7 @@ import {useRenderCount} from "@uidotdev/usehooks"; /** * Component that renders a product. - * Used in the aside (e.g backlog of product) + * Used in the aside (e.g catalog of product) */ export function ProductItem({card_index}) { // #!render_count @@ -16,7 +16,7 @@ export function ProductItem({card_index}) { const getCardDescription = useShopStore((state) => state.getCardDescription); const currency = useShopStore((state) => state.currency); - const onAddCard = useShopStore((state) => state.addCardFromBacklog); + const onAddCard = useShopStore((state) => state.addCardFromCatalog); const card = getCardDescription(card_index); // #!render_count diff --git a/static/js/shop/SearchBar.jsx b/static/js/shop/SearchBar.jsx index 7eceb60..84ff820 100644 --- a/static/js/shop/SearchBar.jsx +++ b/static/js/shop/SearchBar.jsx @@ -5,10 +5,10 @@ export function SearchBar() { const search_bar_value = useShopStore((state) => state.search_bar_value); const updateSearchBar = useShopStore((state) => state.updateSearchBar); return ( -
+
updateSearchBar(event.target.value)} diff --git a/static/js/shop/Shop.jsx b/static/js/shop/Shop.jsx index b6d20ac..4a138df 100644 --- a/static/js/shop/Shop.jsx +++ b/static/js/shop/Shop.jsx @@ -6,7 +6,7 @@ import {useRenderCount} from "@uidotdev/usehooks"; import {Layout} from "./Layout"; -import {Backlog} from "./Backlog"; +import {Catalog} from "./Catalog"; import {OrderPanel} from "./OrderPanel"; import {useShopStore} from "./shop_store"; @@ -18,7 +18,7 @@ export function Shop() { // #!render_count const renderCount = useRenderCount(); - const addCardFromBacklog = useShopStore((state) => state.addCardFromBacklog); + const addCardFromCatalog = useShopStore((state) => state.addCardFromCatalog); const initExtData = useShopStore((state) => state.initExtData); const moveCard = useShopStore((state) => state.moveCard); const deleteCard = useShopStore((state) => state.deleteCard); @@ -30,16 +30,16 @@ export function Shop() { console.log(drop_result) return; } - if (drop_result.source.droppableId === "backlog") - addCardFromBacklog(drop_result.destination.droppableId, drop_result.source.index, drop_result.destination.index); - else if (drop_result.destination.droppableId === "backlog") + if (drop_result.source.droppableId === "catalog") + addCardFromCatalog(drop_result.destination.droppableId, drop_result.source.index, drop_result.destination.index); + else if (drop_result.destination.droppableId === "catalog") deleteCard(drop_result.source.droppableId, drop_result.source.index); else moveCard(drop_result.source.droppableId, drop_result.source.index, drop_result.destination.droppableId, drop_result.destination.index) } useEffect(() => { - addCardFromBacklog(null, [cardIndexById("eem_pwr_mod"), cardIndexById("kasli")], -1, true); + addCardFromCatalog(null, [cardIndexById("eem_pwr_mod"), cardIndexById("kasli")], -1, true); initExtData(); }, []); @@ -50,7 +50,7 @@ export function Shop() { + } main={( { return result; }; -const useBacklog = ((set, get) => ({ +const useCatalog = ((set, get) => ({ cards: shared_data.items, - groups: shared_data.columns.backlog, + groups: shared_data.columns.catalog, cards_list: itemsUnfoldedList, currency: shared_data.currency, pn_to_cards: cards_to_pn_map(shared_data.items), @@ -354,7 +354,7 @@ const useCart = ((set, get) => ({ }) })), setActiveCrate: (id) => set(state => ({active_crate: id})), - _addCardFromBacklog: (crate_to, index_from, index_to) => set(state => { + _addCardFromCatalog: (crate_to, index_from, index_to) => set(state => { const take_from = (true_type_of(index_from) === "array" ? index_from : [index_from]).map((item, _i) => (state.cards_list[item])); const dest = crate_to || state.active_crate; if (!dest) return {}; @@ -525,14 +525,14 @@ const useCart = ((set, get) => ({ get().fillOrderExtData(); }, - addCardFromBacklog: (crate_to, index_from, index_to, just_mounted) => { + addCardFromCatalog: (crate_to, index_from, index_to, just_mounted) => { const dest = crate_to || get().active_crate; if (!dest) { console.warn("No destination"); get().noDestinationWarning(); return {}; } - get()._addCardFromBacklog(dest, index_from, index_to) + get()._addCardFromCatalog(dest, index_from, index_to) get().fillExtData(dest); get().fillWarnings(dest); get().setActiveCrate(dest); @@ -583,7 +583,7 @@ const useCart = ((set, get) => ({ export const useShopStore = createWithEqualityFn((...params) => ({ - ...useBacklog(...params), + ...useCatalog(...params), ...useSearch(...params), ...useCrateModes(...params), ...useCart(...params), diff --git a/static/js/shop/utils.js b/static/js/shop/utils.js index 3ea5ae2..f2f3480 100644 --- a/static/js/shop/utils.js +++ b/static/js/shop/utils.js @@ -1,7 +1,7 @@ 'use strict'; export const data = window.shop_data; -export const itemsUnfoldedList = Array.from(data.columns.backlog.categories.map(groupId => groupId.itemIds).flat()); +export const itemsUnfoldedList = Array.from(data.columns.catalog.categories.map(groupId => groupId.itemIds).flat()); export const productStyle = (style, snapshot, removeAnim, hovered, selected, cart=false) => { const custom = { @@ -9,7 +9,7 @@ export const productStyle = (style, snapshot, removeAnim, hovered, selected, car backgroundColor: (hovered || selected) ? '#eae7f7' : 'initial', }; - if (!cart && snapshot.draggingOver == null && // hack for backlog + if (!cart && snapshot.draggingOver == null && // hack for catalog ((!snapshot.isDragging) // prevent next elements from animation || (snapshot.isDragging && snapshot.isDropAnimating))) { // prevent dragged element from weird animation style.transform = "none"; diff --git a/static/js/shop_data.js b/static/js/shop_data.js index 4155d7b..039881e 100644 --- a/static/js/shop_data.js +++ b/static/js/shop_data.js @@ -1213,12 +1213,12 @@ const shop_data = { columns: { /*** - * backlog is the column containing all items on left aside, + * catalog is the column containing all items on left aside, * name should not change */ - 'backlog': { - id: 'backlog', - title: 'Backlog', + 'catalog': { + id: 'catalog', + title: 'Catalog', /* itemIds define items order - change order to suit your need */ categories: [ { name: 'Core', -- 2.44.1 From 6bfed3e779b5c32fd545d8303581963d556de958 Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Mon, 18 Mar 2024 14:48:16 +0800 Subject: [PATCH 08/15] Show at max only one options notification Closes #124 Signed-off-by: Egor Savkin --- static/js/shop/OptionsWrapper.jsx | 9 ++++++ static/js/shop/options/DialogPopup.jsx | 8 ++++-- static/js/shop/options/Notification.jsx | 38 +++++++++---------------- static/js/shop/shop_store.js | 25 ++++++++++++++++ 4 files changed, 53 insertions(+), 27 deletions(-) diff --git a/static/js/shop/OptionsWrapper.jsx b/static/js/shop/OptionsWrapper.jsx index d5b1e55..72b49e0 100644 --- a/static/js/shop/OptionsWrapper.jsx +++ b/static/js/shop/OptionsWrapper.jsx @@ -11,6 +11,13 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) { const card_id = useShopStore((state) => state.crates[crate_index].items[card_index].id); const options_class = useShopStore((state) => state.crates[crate_index].items[card_index].options_class); const sideMenuIsOpen = useShopStore((state) => state.sideMenuIsOpen); + const _notificationTimer = useShopStore((state) => state.notificationTimer); + const hideNotification = useShopStore((state) => state.hideNotification); + //const notificationCardIndex = useShopStore((state) => state.notificationCardIndex); + //const displayNotification = notificationCrateId === crate_id && notificationCardIndex === card_index; + const displayNotification = useShopStore((state) => + state.notificationCrateId === crate_id && + (state.notificationCardIndex === card_index || (state.crates[crate_index].items.length + (state.notificationCardIndex || -1)) === card_index)); const onOptionsUpdate = useShopStore((state) => state.updateOptions); @@ -25,6 +32,8 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) { first={first} last={last} sideMenuIsOpen={sideMenuIsOpen} + onHideNotification={hideNotification} + displayNotification={displayNotification} target={{ construct: ((outvar, value) => { // #!options_log diff --git a/static/js/shop/options/DialogPopup.jsx b/static/js/shop/options/DialogPopup.jsx index 58a730d..f5efa3a 100644 --- a/static/js/shop/options/DialogPopup.jsx +++ b/static/js/shop/options/DialogPopup.jsx @@ -3,7 +3,8 @@ import {useClickAway} from "./useClickAway"; import {ProcessOptions} from "./Options"; import {Notification} from "./Notification"; -export function DialogPopup({options, data, target, id, big, first, last, options_class, sideMenuIsOpen}) { +export function DialogPopup({options, data, target, id, big, first, last, options_class, + sideMenuIsOpen, displayNotification, onHideNotification}) { const [show, setShow] = useState(false); const ref = useClickAway((e) => { if (e.type === "mousedown") // ignore touchstart @@ -22,8 +23,11 @@ export function DialogPopup({options, data, target, id, big, first, last, option id={"processed_options_notification" + id} tip="Customization options available" sideMenuIsOpen={sideMenuIsOpen} + show={displayNotification} + onHide={onHideNotification} content={ - } /> diff --git a/static/js/shop/options/Notification.jsx b/static/js/shop/options/Notification.jsx index 5fece08..2087a71 100644 --- a/static/js/shop/options/Notification.jsx +++ b/static/js/shop/options/Notification.jsx @@ -1,30 +1,18 @@ import {OverlayTrigger, Tooltip} from "react-bootstrap"; -import React, {useEffect, useState} from "react"; - -export function Notification({id, tip, content, sideMenuIsOpen}) { - const [show, setShow] = useState(false); - - useEffect(() => { - setTimeout(() => { - setShow(true) - }, 100); - - setTimeout(() => { - setShow(false) - }, 5000); - }, []); +import React from "react"; +export function Notification({id, tip, content, sideMenuIsOpen, show, onHide}) { return ( - setShow(false)} - overlay={props => {tip}} - rootClose={!sideMenuIsOpen} - > - {content} - + {tip}} + rootClose={!sideMenuIsOpen} + onToggle={onHide} + > + {content} + ) } \ No newline at end of file diff --git a/static/js/shop/shop_store.js b/static/js/shop/shop_store.js index 7bb29d4..f7a04c8 100644 --- a/static/js/shop/shop_store.js +++ b/static/js/shop/shop_store.js @@ -29,6 +29,28 @@ const useCatalog = ((set, get) => ({ cardIndexById: card_id => get().cards_list.findIndex((element) => (card_id === element)) })); +const useOptionsNotification = ((set, get) => ({ + notificationCrateId: null, + notificationCardIndex: null, + notificationTimer: null, + _showNotification: (crate_id, card_index) => set(state => ({ + notificationCrateId: crate_id, + notificationCardIndex: card_index, + notificationTimer: setTimeout(() => { + state.hideNotification() + }, 5000) + })), + showNotification: (crate_id, card_index) => { + get().hideNotification() + setTimeout(() => get()._showNotification(crate_id, card_index), 100); + }, + hideNotification: () => set(state => ({ + notificationCrateId: null, + notificationCardIndex: null, + notificationTimer: (state.notificationTimer && clearTimeout(state.notificationTimer)) || null, + })) +})); + const useSearch = ((set, get) => ({ search_index: Array.from(Object.values(shared_data.items) .map((card, _) => ( @@ -182,6 +204,7 @@ const useImportJSON = ((set, get) => ({ get().fillExtCrateData(crate.id); }); get()._updateTotalOrderPrice(); + get().showNotification(get().active_crate, null); }, updateImportDescription: (new_description) => set(state => ({ importValue: { @@ -532,6 +555,7 @@ const useCart = ((set, get) => ({ get().noDestinationWarning(); return {}; } + get().showNotification(dest, index_to); get()._addCardFromCatalog(dest, index_from, index_to) get().fillExtData(dest); get().fillWarnings(dest); @@ -583,6 +607,7 @@ const useCart = ((set, get) => ({ export const useShopStore = createWithEqualityFn((...params) => ({ + ...useOptionsNotification(...params), ...useCatalog(...params), ...useSearch(...params), ...useCrateModes(...params), -- 2.44.1 From d3fb46956e2c7f40aa7833ac19beb8b7b30dc26a Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Tue, 19 Mar 2024 10:53:22 +0800 Subject: [PATCH 09/15] Fix notification overlay making "added" notification disappear on touchables When notification doesn't fit viewport on touch-enabled devices, it makes the canvas extend to its boundaries, braking the fixed positioned elements placement Signed-off-by: Egor Savkin --- static/js/shop/options/Notification.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/static/js/shop/options/Notification.jsx b/static/js/shop/options/Notification.jsx index 2087a71..abfb69f 100644 --- a/static/js/shop/options/Notification.jsx +++ b/static/js/shop/options/Notification.jsx @@ -11,6 +11,9 @@ export function Notification({id, tip, content, sideMenuIsOpen, show, onHide}) { overlay={props => {tip}} rootClose={!sideMenuIsOpen} onToggle={onHide} + popperConfig={{ + strategy: 'fixed' + }} > {content} -- 2.44.1 From 5e3a9af7498346f09c6f82039ce8b3aef8aa8a1a Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Tue, 19 Mar 2024 11:10:53 +0800 Subject: [PATCH 10/15] Fix notification remained visible when side menu is opened Signed-off-by: Egor Savkin --- package-lock.json | 156 +++++++++++++++--------------- package.json | 12 +-- static/js/shop/OptionsWrapper.jsx | 2 - static/js/shop/shop_store.js | 8 +- 4 files changed, 91 insertions(+), 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index 50a4f21..2693cf2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,24 +9,24 @@ "version": "1.0.0", "devDependencies": { "@babel/cli": "^7.23.9", - "@babel/core": "^7.23.9", - "@babel/preset-env": "^7.23.9", + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", "@babel/preset-react": "^7.23.3", "@hello-pangea/dnd": "^16.5.0", "@uidotdev/usehooks": "^2.4.1", "babel-loader": "^9.1.3", "babel-preset-minify": "^0.5.2", - "bootstrap": "^5.3.2", + "bootstrap": "^5.3.3", "jquery": "^3.7.1", "json-logic-js": "^2.0.2", "react": "^18.2.0", - "react-bootstrap": "^2.10.0", + "react-bootstrap": "^2.10.2", "react-dom": "^18.2.0", "uuid": "^9.0.1", - "webpack": "^5.90.1", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", "webpack-preprocessor-loader": "^1.3.0", - "zustand": "^4.5.0" + "zustand": "^4.5.2" } }, "node_modules/@ampproject/remapping": { @@ -94,9 +94,9 @@ } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -104,11 +104,11 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -360,9 +360,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -480,14 +480,14 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", + "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", "dev": true, "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -508,9 +508,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1300,14 +1300,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", - "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.0.tgz", + "integrity": "sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.23.3" }, @@ -1667,14 +1667,14 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", - "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", "dev": true, "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-plugin-utils": "^7.24.0", "@babel/helper-validator-option": "^7.23.5", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", @@ -1727,7 +1727,7 @@ "@babel/plugin-transform-new-target": "^7.23.3", "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", "@babel/plugin-transform-numeric-separator": "^7.23.4", - "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", "@babel/plugin-transform-object-super": "^7.23.3", "@babel/plugin-transform-optional-catch-binding": "^7.23.4", "@babel/plugin-transform-optional-chaining": "^7.23.4", @@ -1822,23 +1822,23 @@ } }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", + "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", @@ -1847,8 +1847,8 @@ "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1857,9 +1857,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -2025,9 +2025,9 @@ } }, "node_modules/@react-aria/ssr": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.7.1.tgz", - "integrity": "sha512-ovVPSD1WlRpZHt7GI9DqJrWG3OIYS+NXQ9y5HIewMJpSe+jPQmMQfyRmgX4EnvmxSlp0u04Wg/7oItcoSIb/RA==", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@react-aria/ssr/-/ssr-3.9.2.tgz", + "integrity": "sha512-0gKkgDYdnq1w+ey8KzG9l+H5Z821qh9vVjztk55rUg71vTk/Eaebeir+WtzcLLwTjw3m/asIjx8Y59y1lJZhBw==", "dev": true, "dependencies": { "@swc/helpers": "^0.5.0" @@ -2040,9 +2040,9 @@ } }, "node_modules/@restart/hooks": { - "version": "0.4.11", - "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.11.tgz", - "integrity": "sha512-Ft/ncTULZN6ldGHiF/k5qt72O8JyRMOeg0tApvCni8LkoiEahO+z3TNxfXIVGy890YtWVDvJAl662dVJSJXvMw==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/@restart/hooks/-/hooks-0.4.16.tgz", + "integrity": "sha512-f7aCv7c+nU/3mF7NWLtVVr0Ra80RqsO89hO72r+Y/nvQr5+q0UFGkocElTH6MJApvReVh6JHUFYn2cw1WdHF3w==", "dev": true, "dependencies": { "dequal": "^2.0.3" @@ -2052,9 +2052,9 @@ } }, "node_modules/@restart/ui": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.6.tgz", - "integrity": "sha512-eC3puKuWE1SRYbojWHXnvCNHGgf3uzHCb6JOhnF4OXPibOIPEkR1sqDSkL643ydigxwh+ruCa1CmYHlzk7ikKA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@restart/ui/-/ui-1.6.8.tgz", + "integrity": "sha512-6ndCv3oZ7r9vuP1Ok9KH55TM1/UkdBnP/fSraW0DFDMbPMzWKhVKeFAIEUCRCSdzayjZDcFYK6xbMlipN9dmMA==", "dev": true, "dependencies": { "@babel/runtime": "^7.21.0", @@ -2082,9 +2082,9 @@ } }, "node_modules/@swc/helpers": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", - "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.7.tgz", + "integrity": "sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==", "dev": true, "dependencies": { "tslib": "^2.4.0" @@ -2180,9 +2180,9 @@ "dev": true }, "node_modules/@types/warning": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.0.tgz", - "integrity": "sha512-t/Tvs5qR47OLOr+4E9ckN8AmP2Tf16gWq+/qA4iUGS/OOyHVO8wv2vjJuX8SNOUTJyWb+2t7wJm6cXILFnOROA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/warning/-/warning-3.0.3.tgz", + "integrity": "sha512-D1XC7WK8K+zZEveUPY+cf4+kgauk8N4eHr/XIHXGlGYkHLud6hK9lYfZk1ry1TNh798cZUCgb6MqGEG8DkJt6Q==", "dev": true }, "node_modules/@uidotdev/usehooks": { @@ -2813,9 +2813,9 @@ } }, "node_modules/bootstrap": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", - "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz", + "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==", "dev": true, "funding": [ { @@ -4077,14 +4077,14 @@ } }, "node_modules/react-bootstrap": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.0.tgz", - "integrity": "sha512-87gRP69VAfeU2yKgp8RI3HvzhPNrnYIV2QNranYXataz3ef+k7OhvKGGdxQLQfUsQ2RTmlY66tn4pdFrZ94hNg==", + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.2.tgz", + "integrity": "sha512-UvB7mRqQjivdZNxJNEA2yOQRB7L9N43nBnKc33K47+cH90/ujmnMwatTCwQLu83gLhrzAl8fsa6Lqig/KLghaA==", "dev": true, "dependencies": { "@babel/runtime": "^7.22.5", "@restart/hooks": "^0.4.9", - "@restart/ui": "^1.6.6", + "@restart/ui": "^1.6.8", "@types/react-transition-group": "^4.4.6", "classnames": "^2.3.2", "dom-helpers": "^5.2.1", @@ -4748,9 +4748,9 @@ } }, "node_modules/webpack": { - "version": "5.90.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", - "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", @@ -4974,9 +4974,9 @@ } }, "node_modules/zustand": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.0.tgz", - "integrity": "sha512-zlVFqS5TQ21nwijjhJlx4f9iGrXSL0o/+Dpy4txAP22miJ8Ti6c1Ol1RLNN98BMib83lmDH/2KmLwaNXpjrO1A==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.5.2.tgz", + "integrity": "sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==", "dev": true, "dependencies": { "use-sync-external-store": "1.2.0" diff --git a/package.json b/package.json index 18cf50d..3a93719 100644 --- a/package.json +++ b/package.json @@ -14,22 +14,22 @@ }, "devDependencies": { "@babel/cli": "^7.23.9", - "@babel/core": "^7.23.9", - "@babel/preset-env": "^7.23.9", + "@babel/core": "^7.24.0", + "@babel/preset-env": "^7.24.0", "@babel/preset-react": "^7.23.3", "babel-loader": "^9.1.3", "babel-preset-minify": "^0.5.2", - "bootstrap": "^5.3.2", + "bootstrap": "^5.3.3", "jquery": "^3.7.1", "react": "^18.2.0", - "react-bootstrap": "^2.10.0", + "react-bootstrap": "^2.10.2", "@hello-pangea/dnd": "^16.5.0", "react-dom": "^18.2.0", "uuid": "^9.0.1", - "webpack": "^5.90.1", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", "json-logic-js": "^2.0.2", - "zustand": "^4.5.0", + "zustand": "^4.5.2", "@uidotdev/usehooks":"^2.4.1", "webpack-preprocessor-loader": "^1.3.0" }, diff --git a/static/js/shop/OptionsWrapper.jsx b/static/js/shop/OptionsWrapper.jsx index 72b49e0..73326c2 100644 --- a/static/js/shop/OptionsWrapper.jsx +++ b/static/js/shop/OptionsWrapper.jsx @@ -13,8 +13,6 @@ export function OptionsDialogWrapper({crate_index, card_index, first, last}) { const sideMenuIsOpen = useShopStore((state) => state.sideMenuIsOpen); const _notificationTimer = useShopStore((state) => state.notificationTimer); const hideNotification = useShopStore((state) => state.hideNotification); - //const notificationCardIndex = useShopStore((state) => state.notificationCardIndex); - //const displayNotification = notificationCrateId === crate_id && notificationCardIndex === card_index; const displayNotification = useShopStore((state) => state.notificationCrateId === crate_id && (state.notificationCardIndex === card_index || (state.crates[crate_index].items.length + (state.notificationCardIndex || -1)) === card_index)); diff --git a/static/js/shop/shop_store.js b/static/js/shop/shop_store.js index f7a04c8..08171d2 100644 --- a/static/js/shop/shop_store.js +++ b/static/js/shop/shop_store.js @@ -151,9 +151,15 @@ const useLayout = ((set, get) => ({ showNoDestination: false, timerAdded: null, - switchSideMenu: () => set(state => ({ + _switchSideMenu: () => set(state => ({ sideMenuIsOpen: !state.sideMenuIsOpen })), + switchSideMenu: () => { + if (!get().sideMenuIsOpen) { + get().hideNotification() + } + get()._switchSideMenu(); + }, cardAdded: () => set(state => ({ showCardAddedFeedback: true, showNoDestination: false, -- 2.44.1 From ee6da1b2829aac424536a016e6c451025a5f1f2c Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Wed, 20 Mar 2024 17:07:56 +0800 Subject: [PATCH 11/15] Update bundle Signed-off-by: Egor Savkin --- static/js/shop.bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/shop.bundle.js b/static/js/shop.bundle.js index 26f2e87..d3c26cb 100644 --- a/static/js/shop.bundle.js +++ b/static/js/shop.bundle.js @@ -1,2 +1,2 @@ /*! For license information please see shop.bundle.js.LICENSE.txt */ -(()=>{var e={960:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),s=Symbol.for("react.context"),c=Symbol.for("react.server_context"),u=Symbol.for("react.forward_ref"),d=Symbol.for("react.suspense"),f=Symbol.for("react.suspense_list"),p=Symbol.for("react.memo"),m=Symbol.for("react.lazy");Symbol.for("react.offscreen");Symbol.for("react.module.reference"),t.isContextConsumer=function(e){return function(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case n:switch(e=e.type){case o:case i:case a:case d:case f:return e;default:switch(e=e&&e.$$typeof){case c:case s:case u:case m:case p:case l:return e;default:return t}}case r:return t}}}(e)===s}},896:(e,t,n)=>{"use strict";e.exports=n(960)},80:(e,t)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t{"use strict";var r=n(819),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||o}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,f=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var o=p(n);o&&o!==m&&e(t,o,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,o=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,f=n?Symbol.for("react.forward_ref"):60112,p=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,y=n?Symbol.for("react.block"):60121,b=n?Symbol.for("react.fundamental"):60117,v=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function E(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case a:case l:case i:case p:return e;default:switch(e=e&&e.$$typeof){case c:case f:case h:case g:case s:return e;default:return t}}case o:return t}}}function x(e){return E(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=f,t.Fragment=a,t.Lazy=h,t.Memo=g,t.Portal=o,t.Profiler=l,t.StrictMode=i,t.Suspense=p,t.isAsyncMode=function(e){return x(e)||E(e)===u},t.isConcurrentMode=x,t.isContextConsumer=function(e){return E(e)===c},t.isContextProvider=function(e){return E(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return E(e)===f},t.isFragment=function(e){return E(e)===a},t.isLazy=function(e){return E(e)===h},t.isMemo=function(e){return E(e)===g},t.isPortal=function(e){return E(e)===o},t.isProfiler=function(e){return E(e)===l},t.isStrictMode=function(e){return E(e)===i},t.isSuspense=function(e){return E(e)===p},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===d||e===l||e===i||e===p||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===s||e.$$typeof===c||e.$$typeof===f||e.$$typeof===b||e.$$typeof===v||e.$$typeof===w||e.$$typeof===y)},t.typeOf=E},819:(e,t,n)=>{"use strict";e.exports=n(560)},948:e=>{"use strict";e.exports=function(e,t,n,r,o,a,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,o,a,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},344:function(e,t,n){var r,o;r=function(){"use strict";Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)});var e={},t={"==":function(e,t){return e==t},"===":function(e,t){return e===t},"!=":function(e,t){return e!=t},"!==":function(e,t){return e!==t},">":function(e,t){return e>t},">=":function(e,t){return e>=t},"<":function(e,t,n){return void 0===n?e=t?[]:r}};return e.is_logic=function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&1===Object.keys(e).length},e.truthy=function(e){return!(Array.isArray(e)&&0===e.length||!e)},e.get_operator=function(e){return Object.keys(e)[0]},e.get_values=function(t){return t[e.get_operator(t)]},e.apply=function(n,r){if(Array.isArray(n))return n.map((function(t){return e.apply(t,r)}));if(!e.is_logic(n))return n;var o,a,i,l,s,c=e.get_operator(n),u=n[c];if(Array.isArray(u)||(u=[u]),"if"===c||"?:"==c){for(o=0;o0){var d=String(c).split("."),f=t;for(o=0;o{"use strict";var r=n(143);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},268:(e,t,n)=>{e.exports=n(776)()},143:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},516:(e,t,n)=>{"use strict";var r=n(504),o=n(712);function a(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n
); } } -export function LineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes}) { +export function LineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes, validator}) { return ; + id={id} data={data} classes={classes} validator={validator && Validation[validator.name](validator.params)}/>; } \ No newline at end of file diff --git a/static/js/shop/options/components/SwitchLine.jsx b/static/js/shop/options/components/SwitchLine.jsx index 7765da6..39dcd32 100644 --- a/static/js/shop/options/components/SwitchLine.jsx +++ b/static/js/shop/options/components/SwitchLine.jsx @@ -1,5 +1,6 @@ import React, {Component} from "react"; import {Tip} from "./Tip"; +import {Validation} from "../validation"; class SwitchLine extends Component { constructor(props) { @@ -7,7 +8,8 @@ class SwitchLine extends Component { // Initialize the state object with the initial values from the props this.state = { text: props.outvar in props.data ? props.data[props.outvar].text : (props.fallback ? props.fallback.text : ""), - checked: props.outvar in props.data ? props.data[props.outvar].checked : (props.fallback ? props.fallback.checked : false) + checked: props.outvar in props.data ? props.data[props.outvar].checked : (props.fallback ? props.fallback.checked : false), + valid: true }; // Bind the event handler to this this.handleText = this.handleText.bind(this); @@ -18,7 +20,8 @@ class SwitchLine extends Component { handleText(element) { let new_state = { ...this.state, - text: element.target.value + text: element.target.value, + valid: this.props.validator ? this.props.validator(element.target.value) : true } this.setState(new_state); this.props.target.update(this.props.outvar, new_state); @@ -39,6 +42,7 @@ class SwitchLine extends Component { return { checked: props.data[props.outvar].checked, text: props.data[props.outvar].text, + valid: this.props.validator ? this.props.validator(props.data[props.outvar].text) : true } } return null @@ -64,14 +68,14 @@ class SwitchLine extends Component { {this.props.tip && }
-
); } } -export function SwitchLineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes}) { +export function SwitchLineWrapper(target, id, data, {title, fallback, outvar, icon, tip, classes, validator}) { return ; + id={id} data={data} classes={classes} validator={validator && Validation[validator.name](validator.params)}/>; } diff --git a/static/js/shop/options/validation.js b/static/js/shop/options/validation.js new file mode 100644 index 0000000..d0ee431 --- /dev/null +++ b/static/js/shop/options/validation.js @@ -0,0 +1,51 @@ + + +const ipv4 = (params) => { + const ipv4WithMaskPattern = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/(0|1[0-9]|2[0-9]|3[0-2]|[0-9])$/; + return (text) => { + return ipv4WithMaskPattern.test(text); + } +} + +const ipv6 = (params) => { + const ipv6WithMaskPattern = /(^\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\s*$)|(^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(\/(\d{1,2}|1[0-1]\d|12[0-8]))(%.+)?\s*$)/; + + + return (text) => { + return ipv6WithMaskPattern.test(text); + } +} + +const ipv4or6 = (params) => { + const ipv4Local = ipv4(params); + const ipv6Local = ipv6(params); + return (text) => { + return ipv4Local(text) || ipv6Local(text); + } +} + +const frequency = (params) => { + const factors = { + "mhz": 1e6, + "khz": 1e3, + "hz": 1e1, + "ghz": 1e9, + }; + + return (text) => { + const splited = text.split(/(\s+)/); + const numerator = parseFloat(splited[0]); + if (splited.length !== 3 || isNaN(numerator)) return false; + const factor = factors[splited[2].toLowerCase()]; + if (!factor) return false; + const realFreq = factor * numerator; + return realFreq >= (params.min || 10*factors.mhz) && realFreq <= (params.max || 1*factors.ghz); + } +} + +export const Validation = { + ipv4: ipv4, + ipv6: ipv6, + ipv4or6: ipv4or6, + frequency: frequency +}; \ No newline at end of file diff --git a/static/js/shop_data.js b/static/js/shop_data.js index 039881e..f665fd2 100644 --- a/static/js/shop_data.js +++ b/static/js/shop_data.js @@ -194,9 +194,14 @@ const shop_data = { ] }, [ - {type: "Line", args: {title: "IPv4", outvar: "ipv4", fallback: "192.168.1.75/24", tip: "Set up IPv4 address used by core device"}}, - {type: "SwitchLine", args: {title: "IPv6", outvar: "ipv6"}}, - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}, tip: "Use external clock reference: 10, 80 (beta), 100 or 125 MHz. Other variants may be provided if needed."}} + {type: "Line", args: {title: "IPv4", outvar: "ipv4", fallback: "192.168.1.75/24", + tip: "Set up IPv4 address and mask used by core device", validator: {name: "ipv4"}}}, + {type: "SwitchLine", args: {title: "IPv6", outvar: "ipv6", + tip: "Set up IPv6 address and prefix used by core device", + validator: {name: "ipv6"}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}, + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + tip: "Use external clock reference: 10, 80 (beta), 100 or 125 MHz. Other variants may be provided if needed."}} ], [ {type: "Switch", args: {title: "Optical fiber", outvar: "optics", tip: "Use optical fiber instead of direct attach copper cable"}}, @@ -262,9 +267,17 @@ const shop_data = { ] }, [ - {type: "Line", args: {title: "IPv4", outvar: "ipv4", fallback: "192.168.1.75/24", tip: "Set up IPv4 address used by core device"}}, - {type: "SwitchLine", args: {title: "IPv6", outvar: "ipv6"}}, - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}, tip: "Use external clock reference: 10, 80 (beta), 100 or 125 MHz. Other variants may be provided if needed."}} + {type: "Line", args: {title: "IPv4", outvar: "ipv4", + validator: {name: "ipv4"}, + fallback: "192.168.1.75/24", + tip: "Set up IPv4 address used by core device"}}, + {type: "SwitchLine", args: {title: "IPv6", outvar: "ipv6", + tip: "Set up IPv6 address and prefix used by core device", + validator: {name: "ipv6"}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + fallback: {text: "125 MHz", checked: false}, + tip: "Use external clock reference: 10, 80 (beta), 100 or 125 MHz. Other variants may be provided if needed."}} ], [ {type: "Switch", args: {title: "Optical fiber", outvar: "optics", tip: "Use optical fiber instead of direct attach copper cable"}}, @@ -658,7 +671,9 @@ const shop_data = { "if": [ {"var": "mono_eem"}, [ - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + fallback: {text: "125 MHz", checked: false}}}, ], [ {type: "Switch", args: {title: "Synchronization", outvar: "sync", tip: "Synchronize phases across Urukuls"}}, @@ -667,7 +682,9 @@ const shop_data = { {"var": "sync"}, null, [ - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + fallback: {text: "125 MHz", checked: false}}}, { "if": [ {"var": "ext_data.has_sampler"}, @@ -716,7 +733,9 @@ const shop_data = { datasheet_name: '4410/4412 Urukul datasheet', options: [ {type: "Switch", args: {title: "Use 1 EEM", outvar: "mono_eem", tip: "Use one EEM port setup. RF switch and synchronization will be unavailable."}}, - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}} + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + fallback: {text: "125 MHz", checked: false}}} ], size: 'small', type: 'urukul', @@ -747,7 +766,9 @@ const shop_data = { 'The upconverter is optional, if you would like the baseband version please leave us a note.' ], options: [ - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 1e9}}, + fallback: {text: "125 MHz", checked: false}}}, {type: "Radio", args: {title: "Variant", outvar: "variant", variants: ["Baseband", "Upconverter"], fallback: 1}}, ], size: 'small', @@ -1025,7 +1046,10 @@ const shop_data = { 'Can be controlled by Kasli or work stand-alone with PoE supply.' ], options: [ - {type: "SwitchLine", args: {title: "IP", outvar: "ip", fallback: {text: "DHCP", checked: false}, tip: "Set up IP address used by the device"}}, + {type: "SwitchLine", args: {title: "IP", outvar: "ip", + validator: {name: "ipv4or6"}, + fallback: {text: "DHCP", checked: false}, + tip: "Set up IP address used by the device"}}, {type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}}, {type: "Switch", args: {title: "Term #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}}, {type: "Switch", args: {title: "Term #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}} @@ -1057,7 +1081,9 @@ const shop_data = { 'Large frequency changes take several milliseconds.', ], options: [ - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}} + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 600e6}}, + fallback: {text: "125 MHz", checked: false}}} ], size: 'small', type: null, @@ -1084,7 +1110,9 @@ const shop_data = { 'Each Almazny channel outputs twice the frequency of its corresponding Mirny channel.', ], options: [ - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}} + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + validator: {name: "frequency", params: {min: 10e6, max: 600e6}}, + fallback: {text: "125 MHz", checked: false}}} ], size: 'big', type: null, @@ -1166,9 +1194,13 @@ const shop_data = { 'AD9959 DDS (500MSPS, 10-bit).' ], options: [ - {type: "SwitchLine", args: {title: "IP", outvar: "ip", fallback: {text: "DHCP", checked: false}, tip: "Set up IP address used by the device"}}, + {type: "SwitchLine", args: {title: "IP", outvar: "ip", + validator: {name: "ipv4or6"}, + fallback: {text: "DHCP", checked: false}, + tip: "Set up IP address used by the device"}}, {type: "Switch", args: {title: "Ext power", outvar: "ext_pwr", "tip": "Use external power supply in order to reduce number of used EEM connectors"}}, - {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", fallback: {text: "125 MHz", checked: false}}}, + {type: "SwitchLine", args: {title: "Ext CLK", outvar: "ext_clk", + fallback: {text: "125 MHz", checked: false}, validator: {name: "frequency", params: {min: 10e6, max: 1e9}}}}, {type: "Switch", args: {title: "Termination #0", outvar: "term_0", tip: "Enable termination on ADC channel #0"}}, {type: "Switch", args: {title: "Termination #1", outvar: "term_1", tip: "Enable termination on ADC channel #1"}} ], -- 2.44.1 From 4448029757dfcebcd38956b46442a7315f1bbf6c Mon Sep 17 00:00:00 2001 From: Egor Savkin Date: Mon, 8 Apr 2024 17:30:10 +0800 Subject: [PATCH 14/15] Update bundle and make example configuration correct Signed-off-by: Egor Savkin --- static/js/shop.bundle.js | 2 +- static/js/shop/ImportJSON.jsx | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/static/js/shop.bundle.js b/static/js/shop.bundle.js index 48d5d4b..110a548 100644 --- a/static/js/shop.bundle.js +++ b/static/js/shop.bundle.js @@ -1,2 +1,2 @@ /*! For license information please see shop.bundle.js.LICENSE.txt */ -(()=>{var e={513:(e,t)=>{"use strict";var n=Symbol.for("react.element"),r=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),a=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),l=Symbol.for("react.provider"),s=Symbol.for("react.context"),c=Symbol.for("react.server_context"),u=Symbol.for("react.forward_ref"),d=Symbol.for("react.suspense"),p=Symbol.for("react.suspense_list"),f=Symbol.for("react.memo"),m=Symbol.for("react.lazy");Symbol.for("react.offscreen");Symbol.for("react.module.reference"),t.isContextConsumer=function(e){return function(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case n:switch(e=e.type){case o:case i:case a:case d:case p:return e;default:switch(e=e&&e.$$typeof){case c:case s:case u:case m:case f:case l:return e;default:return t}}case r:return t}}}(e)===s}},749:(e,t,n)=>{"use strict";e.exports=n(513)},485:(e,t)=>{var n;!function(){"use strict";var r={}.hasOwnProperty;function o(){for(var e=[],t=0;t{"use strict";var r=n(404),o={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},a={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},i={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},l={};function s(e){return r.isMemo(e)?i:l[e.$$typeof]||o}l[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},l[r.Memo]=i;var c=Object.defineProperty,u=Object.getOwnPropertyNames,d=Object.getOwnPropertySymbols,p=Object.getOwnPropertyDescriptor,f=Object.getPrototypeOf,m=Object.prototype;e.exports=function e(t,n,r){if("string"!=typeof n){if(m){var o=f(n);o&&o!==m&&e(t,o,r)}var i=u(n);d&&(i=i.concat(d(n)));for(var l=s(t),g=s(n),h=0;h{"use strict";var n="function"==typeof Symbol&&Symbol.for,r=n?Symbol.for("react.element"):60103,o=n?Symbol.for("react.portal"):60106,a=n?Symbol.for("react.fragment"):60107,i=n?Symbol.for("react.strict_mode"):60108,l=n?Symbol.for("react.profiler"):60114,s=n?Symbol.for("react.provider"):60109,c=n?Symbol.for("react.context"):60110,u=n?Symbol.for("react.async_mode"):60111,d=n?Symbol.for("react.concurrent_mode"):60111,p=n?Symbol.for("react.forward_ref"):60112,f=n?Symbol.for("react.suspense"):60113,m=n?Symbol.for("react.suspense_list"):60120,g=n?Symbol.for("react.memo"):60115,h=n?Symbol.for("react.lazy"):60116,b=n?Symbol.for("react.block"):60121,v=n?Symbol.for("react.fundamental"):60117,y=n?Symbol.for("react.responder"):60118,w=n?Symbol.for("react.scope"):60119;function E(e){if("object"==typeof e&&null!==e){var t=e.$$typeof;switch(t){case r:switch(e=e.type){case u:case d:case a:case l:case i:case f:return e;default:switch(e=e&&e.$$typeof){case c:case p:case h:case g:case s:return e;default:return t}}case o:return t}}}function x(e){return E(e)===d}t.AsyncMode=u,t.ConcurrentMode=d,t.ContextConsumer=c,t.ContextProvider=s,t.Element=r,t.ForwardRef=p,t.Fragment=a,t.Lazy=h,t.Memo=g,t.Portal=o,t.Profiler=l,t.StrictMode=i,t.Suspense=f,t.isAsyncMode=function(e){return x(e)||E(e)===u},t.isConcurrentMode=x,t.isContextConsumer=function(e){return E(e)===c},t.isContextProvider=function(e){return E(e)===s},t.isElement=function(e){return"object"==typeof e&&null!==e&&e.$$typeof===r},t.isForwardRef=function(e){return E(e)===p},t.isFragment=function(e){return E(e)===a},t.isLazy=function(e){return E(e)===h},t.isMemo=function(e){return E(e)===g},t.isPortal=function(e){return E(e)===o},t.isProfiler=function(e){return E(e)===l},t.isStrictMode=function(e){return E(e)===i},t.isSuspense=function(e){return E(e)===f},t.isValidElementType=function(e){return"string"==typeof e||"function"==typeof e||e===a||e===d||e===l||e===i||e===f||e===m||"object"==typeof e&&null!==e&&(e.$$typeof===h||e.$$typeof===g||e.$$typeof===s||e.$$typeof===c||e.$$typeof===p||e.$$typeof===v||e.$$typeof===y||e.$$typeof===w||e.$$typeof===b)},t.typeOf=E},404:(e,t,n)=>{"use strict";e.exports=n(72)},311:e=>{"use strict";e.exports=function(e,t,n,r,o,a,i,l){if(!e){var s;if(void 0===t)s=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,o,a,i,l],u=0;(s=new Error(t.replace(/%s/g,(function(){return c[u++]})))).name="Invariant Violation"}throw s.framesToPop=1,s}}},678:function(e,t,n){var r,o;r=function(){"use strict";Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)});var e={},t={"==":function(e,t){return e==t},"===":function(e,t){return e===t},"!=":function(e,t){return e!=t},"!==":function(e,t){return e!==t},">":function(e,t){return e>t},">=":function(e,t){return e>=t},"<":function(e,t,n){return void 0===n?e=t?[]:r}};return e.is_logic=function(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)&&1===Object.keys(e).length},e.truthy=function(e){return!(Array.isArray(e)&&0===e.length||!e)},e.get_operator=function(e){return Object.keys(e)[0]},e.get_values=function(t){return t[e.get_operator(t)]},e.apply=function(n,r){if(Array.isArray(n))return n.map((function(t){return e.apply(t,r)}));if(!e.is_logic(n))return n;var o,a,i,l,s,c=e.get_operator(n),u=n[c];if(Array.isArray(u)||(u=[u]),"if"===c||"?:"==c){for(o=0;o0){var d=String(c).split("."),p=t;for(o=0;o{"use strict";var r=n(925);function o(){}function a(){}a.resetWarningCache=o,e.exports=function(){function e(e,t,n,o,a,i){if(i!==r){var l=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw l.name="Invariant Violation",l}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:a,resetWarningCache:o};return n.PropTypes=n,n}},556:(e,t,n)=>{e.exports=n(694)()},925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},551:(e,t,n)=>{"use strict";var r=n(540),o=n(982);function a(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n