Add legend to help users discover options

Signed-off-by: Egor Savkin <es@m-labs.hk>
pull/113/head
Egor Savkin 2023-12-15 17:26:52 +08:00
parent a03a151c42
commit 14c365b20f
10 changed files with 102 additions and 19 deletions

View File

@ -212,10 +212,22 @@ button {
display: flex;
font-size: .8rem;
> p {
> .description {
width: 50%;
padding-right: 30px;
}
> .legend {
//d-flex justify-content-end align-self-start
display: flex;
justify-content: end;
align-self: start;
width: 50%;
table {
width: 75%;
max-width: 300px;
}
}
}
.summary {
@ -560,6 +572,7 @@ button {
.crate-bar {
width: 100%;
font-size: 0.9rem;
.crate-mode {
text-align: left;
@ -572,6 +585,7 @@ button {
color: inherit;
text-decoration: none;
padding-bottom: 5px;
display: inline-block;
}
a.active {
font-weight: 700;
@ -663,17 +677,13 @@ button {
color: white;
font-weight: 700;
font-size: .6rem;
padding: .8rem 1rem;
padding: .5rem .8rem;
box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.15);
text-align: left;
p {
margin-bottom: 0;
}
p + p {
padding-bottom: 8px;
}
}
.k-popup-connectors {

View File

@ -108,9 +108,17 @@
}
#root-shop .panel .control > .description,
#root-shop .panel .control > .legend,
#root-shop .crate-mode {
width: 100%;
}
#root-shop .panel .control > .legend {
justify-content: center;
align-self: center;
}
#root-shop .panel .control > .legend tr {
padding: 0;
}
#root-shop .crate-mode {
text-align: left;
@ -308,12 +316,23 @@
}
#root-shop .panel .control > .description,
#root-shop .crate-mode {
#root-shop .panel .control > .legend {
width: 100%;
}
#root-shop .panel .control > .legend {
justify-content: center;
align-self: center;
}
#root-shop .panel .control > .legend tr {
padding: 0;
}
#root-shop .crate-mode {
#root-shop .panel .crate .crate-bar .crate-mode {
text-align: left;
width: 50%;
}
#root-shop .panel .crate .crate-bar .crate-mode a {
display: block;
}
#root-shop .panel .summary {
@ -571,12 +590,23 @@
}
#root-shop .panel .control > .description,
#root-shop .panel .control > .crate-mode {
#root-shop .panel .control > .legend {
width: 100%;
}
#root-shop .panel .control > .legend {
justify-content: center;
align-self: center;
}
#root-shop .panel .control > .legend tr {
padding: 0;
}
#root-shop .panel .control > .crate-mode {
#root-shop .panel .crate .crate-bar .crate-mode {
text-align: left;
width: 50%;
}
#root-shop .panel .crate .crate-bar .crate-mode a {
display: block;
}
#root-shop .panel .summary {

File diff suppressed because one or more lines are too long

View File

@ -26,10 +26,10 @@ export function Crate({crate_index}) {
return (
<div className="crate">
<div className="crate-bar d-inline-flex">
<div className="crate-bar d-inline-flex justify-content-between">
<CrateMode crate_index={crate_index}/>
<div className="delete-crate align-self-end align-content-end justify-content-end" onClick={() => onDeleteCrate(crate.id)}>
<div className="delete-crate align-self-start align-content-start justify-content-end" onClick={() => onDeleteCrate(crate.id)}>
Delete crate <img src="/images/shop/icon-remove.svg" alt="remove"/>
</div>
</div>

View File

@ -24,7 +24,7 @@ export function CrateMode({crate_index}) {
{modes_order.map((mode_name, _) => (
<a
key={mode_name}
className={crate.crate_mode === mode_name ? 'active' : ''}
className={(crate.crate_mode === mode_name ? 'active' : '') }
onClick={() => setMode(crate.id, mode_name)}
href="#"
role="button">{crate_modes[mode_name].name}</a>

21
static/js/shop/Legend.jsx Normal file
View File

@ -0,0 +1,21 @@
import React from "react";
import {useShopStore} from "./shop_store";
export function LegendItem({icon, description}) {
return (
<tr>
<td className="p-1"><img className="" width="20px" src={icon} alt={description}/></td>
<td className="p-1"><span> {description} </span></td>
</tr>
)
}
export function Legend() {
const legend = useShopStore(state => state.legend);
return <table>
<tbody>
{legend.map((item, i) => <LegendItem key={"legend_item"+i} icon={item.icon} description={item.description}/>)}
</tbody>
</table>
}

View File

@ -13,7 +13,7 @@ import {useRenderCount} from "@uidotdev/usehooks";
* Component that renders all things for order.
* It acts like-a layout, this component do nothing more.
*/
export function OrderPanel({title, description}) {
export function OrderPanel({title, description, legend}) {
// #!render_count
const renderCount = useRenderCount();
const isMobile = useShopStore((state) => state.isMobile);
@ -26,8 +26,13 @@ export function OrderPanel({title, description}) {
<h2>{title}</h2>
<div className="control">
<div className="control justify-content-between">
{description}
<div className="legend">
{legend}
</div>
</div>
<div>

View File

@ -9,6 +9,7 @@ import {Layout} from "./Layout";
import {Backlog} from "./Backlog";
import {OrderPanel} from "./OrderPanel";
import {useShopStore} from "./shop_store";
import {Legend} from "./Legend";
/**
* Component that renders the entire shop
@ -59,6 +60,7 @@ export function Shop() {
this ordering system, or if you need other configurations, email us directly anytime
at <a href="mailto:sales@m-labs.hk">sales@m-labs.hk</a>. The price is estimated and must
be confirmed by a quote.</p>)}
legend={(<Legend/>)}
/>
)}>
</Layout>

View File

@ -1,6 +1,6 @@
'use strict';
import {create} from "zustand";
import {createWithEqualityFn} from "zustand/traditional";
import {data as shared_data, itemsUnfoldedList} from "./utils";
import {true_type_of} from "./options/utils";
import {v4 as uuidv4} from "uuid";
@ -28,6 +28,10 @@ const useBacklog = ((set, get) => ({
cardIndexById: card_id => get().cards_list.findIndex((element) => (card_id === element))
}));
const useLegend = ((set, get) => ({
legend: shared_data.legend
}))
const useCrateModes = ((set, get) => ({
crate_modes: shared_data.crateModes,
modes_order: shared_data.crateModeOrder,
@ -389,7 +393,7 @@ const useCart = ((set, get) => ({
setCrateMode: (id, mode) => {
get()._setCrateMode(id, mode)
get().fillExtData(crate_id);
get().fillExtData(id);
get().fillWarnings(id);
get().setActiveCrate(id);
},
@ -435,7 +439,7 @@ const useCart = ((set, get) => ({
}))
export const useShopStore = create((...params) => ({
export const useShopStore = createWithEqualityFn((...params) => ({
...useBacklog(...params),
...useCrateModes(...params),
...useCart(...params),
@ -443,4 +447,5 @@ export const useShopStore = create((...params) => ({
...useLayout(...params),
...useHighlighted(...params),
...useImportJSON(...params),
...useLegend(...params),
}))

View File

@ -3,6 +3,16 @@ const shop_data = {
API_RFQ: 'https://hooks.m-labs.hk/rfq',
currency: 'USD',
legend: [
{icon: "/images/shop/icon-customize.svg", description: "cards configuration available"},
{icon: "/images/shop/icon-add.svg", description: "add a card or crate to the order"},
{icon: "/images/shop/icon-remove.svg", description: "remove a card or crate from the order"},
{icon: "/images/shop/icon-clear.svg", description: "remove all the cards from the crate"},
{icon: "/images/shop/icon-warning.svg", description: "the card or crate contains errors"},
{icon: "/images/shop/icon-reminder.svg", description: "suggestions or hints available"},
],
crateModes: {
rack: {
id: 'rack',