1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-29 10:24:20 +01:00

(quality) Improve responsive

This commit is contained in:
vincent 2022-09-20 15:21:44 +02:00
parent 2e1784b291
commit 75d327f410
18 changed files with 392 additions and 135 deletions

View File

@ -144,6 +144,9 @@ const StoreCart: React.FC<StoreCartProps> = ({ onSuccess, onError, currentUser,
<div className="ref"> <div className="ref">
<span>{t('app.public.store_cart.reference_short')} {item.orderable_ref || ''}</span> <span>{t('app.public.store_cart.reference_short')} {item.orderable_ref || ''}</span>
<p>{item.orderable_name}</p> <p>{item.orderable_name}</p>
{item.quantity_min > 1 &&
<span className='min'>{t('app.public.store_cart.minimum_purchase')}{item.quantity_min}</span>
}
</div> </div>
<div className="actions"> <div className="actions">
<div className='price'> <div className='price'>

View File

@ -6,7 +6,7 @@ import { FabButton } from '../base/fab-button';
import { User } from '../../models/user'; import { User } from '../../models/user';
import { FabStateLabel } from '../base/fab-state-label'; import { FabStateLabel } from '../base/fab-state-label';
import OrderLib from '../../lib/order'; import OrderLib from '../../lib/order';
import { ArrowClockwise } from 'phosphor-react'; import { PlusCircle } from 'phosphor-react';
interface OrderItemProps { interface OrderItemProps {
order?: Order, order?: Order,
@ -37,11 +37,9 @@ export const OrderItem: React.FC<OrderItemProps> = ({ order, currentUser }) => {
return ( return (
<div className='order-item'> <div className='order-item'>
<p className="ref">{order.reference}</p> <p className="ref">{order.reference}</p>
<div>
<FabStateLabel status={OrderLib.statusColor(order)} background> <FabStateLabel status={OrderLib.statusColor(order)} background>
{t(`app.shared.store.order_item.state.${OrderLib.statusText(order)}`)} {t(`app.shared.store.order_item.state.${OrderLib.statusText(order)}`)}
</FabStateLabel> </FabStateLabel>
</div>
{isPrivileged() && {isPrivileged() &&
<div className='client'> <div className='client'>
<span>{t('app.shared.store.order_item.client')}</span> <span>{t('app.shared.store.order_item.client')}</span>
@ -52,7 +50,7 @@ export const OrderItem: React.FC<OrderItemProps> = ({ order, currentUser }) => {
<span>{t('app.shared.store.order_item.created_at')}</span> <span>{t('app.shared.store.order_item.created_at')}</span>
<p>{FormatLib.date(order.created_at)} <p>{FormatLib.date(order.created_at)}
<div className="fab-tooltip"> <div className="fab-tooltip">
<span className="trigger"><ArrowClockwise size={16} weight="light" /></span> <span className="trigger"><PlusCircle size={16} weight="light" /></span>
<div className="content"> <div className="content">
{t('app.shared.store.order_item.last_update')}<br /> {t('app.shared.store.order_item.last_update')}<br />
{FormatLib.date(order.updated_at)} {FormatLib.date(order.updated_at)}

View File

@ -15,7 +15,7 @@ import { FormInput } from '../form/form-input';
import OrderAPI from '../../api/order'; import OrderAPI from '../../api/order';
import { Order, OrderIndexFilter } from '../../models/order'; import { Order, OrderIndexFilter } from '../../models/order';
import { FabPagination } from '../base/fab-pagination'; import { FabPagination } from '../base/fab-pagination';
import { X } from 'phosphor-react'; import { CaretDoubleUp, X } from 'phosphor-react';
declare const Application: IApplication; declare const Application: IApplication;
@ -54,6 +54,7 @@ const Orders: React.FC<OrdersProps> = ({ currentUser, onError }) => {
const [orders, setOrders] = useState<Array<Order>>([]); const [orders, setOrders] = useState<Array<Order>>([]);
const [filters, setFilters] = useImmer<OrderIndexFilter>(window[FablabOrdersFilters] || initFilters); const [filters, setFilters] = useImmer<OrderIndexFilter>(window[FablabOrdersFilters] || initFilters);
const [accordion, setAccordion] = useState({}); const [accordion, setAccordion] = useState({});
const [filtersPanel, setFiltersPanel] = useState<boolean>(true);
const [pageCount, setPageCount] = useState<number>(0); const [pageCount, setPageCount] = useState<number>(0);
const [totalCount, setTotalCount] = useState<number>(0); const [totalCount, setTotalCount] = useState<number>(0);
const [reference, setReference] = useState<string>(filters.reference); const [reference, setReference] = useState<string>(filters.reference);
@ -256,14 +257,15 @@ const Orders: React.FC<OrdersProps> = ({ currentUser, onError }) => {
} }
</header> </header>
<div className="store-filters"> <aside className={`store-filters ${filtersPanel ? '' : 'collapsed'}`}>
<header> <header>
<h3>{t('app.admin.store.orders.filter')}</h3> <h3>{t('app.admin.store.orders.filter')}</h3>
<div className='grpBtn'> <div className='grpBtn'>
<FabButton onClick={clearAllFilters} className="is-black">{t('app.admin.store.orders.filter_clear')}</FabButton> <FabButton onClick={clearAllFilters} className="is-black">{t('app.admin.store.orders.filter_clear')}</FabButton>
<CaretDoubleUp className='filters-toggle' size={16} weight="bold" onClick={() => setFiltersPanel(!filtersPanel)} />
</div> </div>
</header> </header>
<div className="accordion"> <div className="grp accordion">
<AccordionItem id={0} <AccordionItem id={0}
isOpen={accordion[0]} isOpen={accordion[0]}
onChange={handleAccordion} onChange={handleAccordion}
@ -331,7 +333,7 @@ const Orders: React.FC<OrdersProps> = ({ currentUser, onError }) => {
</div> </div>
</AccordionItem> </AccordionItem>
</div> </div>
</div> </aside>
<div className="store-list"> <div className="store-list">
<StoreListHeader <StoreListHeader

View File

@ -13,7 +13,7 @@ import ProductAPI from '../../api/product';
import ProductCategoryAPI from '../../api/product-category'; import ProductCategoryAPI from '../../api/product-category';
import MachineAPI from '../../api/machine'; import MachineAPI from '../../api/machine';
import { AccordionItem } from './accordion-item'; import { AccordionItem } from './accordion-item';
import { X } from 'phosphor-react'; import { CaretDoubleUp, X } from 'phosphor-react';
import { StoreListHeader } from './store-list-header'; import { StoreListHeader } from './store-list-header';
import { FabPagination } from '../base/fab-pagination'; import { FabPagination } from '../base/fab-pagination';
import ProductLib from '../../lib/product'; import ProductLib from '../../lib/product';
@ -47,6 +47,7 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
const [machines, setMachines] = useState<checklistOption[]>([]); const [machines, setMachines] = useState<checklistOption[]>([]);
const [update, setUpdate] = useState(false); const [update, setUpdate] = useState(false);
const [accordion, setAccordion] = useState({}); const [accordion, setAccordion] = useState({});
const [filtersPanel, setFiltersPanel] = useState<boolean>(true);
const [pageCount, setPageCount] = useState<number>(0); const [pageCount, setPageCount] = useState<number>(0);
const [currentPage, setCurrentPage] = useState<number>(1); const [currentPage, setCurrentPage] = useState<number>(1);
@ -242,14 +243,15 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
<FabButton className="main-action-btn" onClick={newProduct}>{t('app.admin.store.products.create_a_product')}</FabButton> <FabButton className="main-action-btn" onClick={newProduct}>{t('app.admin.store.products.create_a_product')}</FabButton>
</div> </div>
</header> </header>
<div className='store-filters'> <aside className={`store-filters ${filtersPanel ? '' : 'collapsed'}`}>
<header> <header>
<h3>{t('app.admin.store.products.filter')}</h3> <h3>{t('app.admin.store.products.filter')}</h3>
<div className='grpBtn'> <div className='grpBtn'>
<FabButton onClick={clearAllFilters} className="is-black">{t('app.admin.store.products.filter_clear')}</FabButton> <FabButton onClick={clearAllFilters} className="is-black">{t('app.admin.store.products.filter_clear')}</FabButton>
<CaretDoubleUp className='filters-toggle' size={16} weight="bold" onClick={() => setFiltersPanel(!filtersPanel)} />
</div> </div>
</header> </header>
<div className='accordion'> <div className='grp accordion'>
<AccordionItem id={0} <AccordionItem id={0}
isOpen={accordion[0]} isOpen={accordion[0]}
onChange={handleAccordion} onChange={handleAccordion}
@ -328,7 +330,7 @@ const Products: React.FC<ProductsProps> = ({ onSuccess, onError }) => {
</div> </div>
</AccordionItem> </AccordionItem>
</div> </div>
</div> </aside>
<div className='store-list'> <div className='store-list'>
<StoreListHeader <StoreListHeader
productsCount={filteredProductsList.length} productsCount={filteredProductsList.length}

View File

@ -81,6 +81,9 @@ export const StoreProductItem: React.FC<StoreProductItemProps> = ({ product, car
<img src={productImageUrl(product)} alt='' /> <img src={productImageUrl(product)} alt='' />
</div> </div>
<p className="name">{product.name}</p> <p className="name">{product.name}</p>
{product.quantity_min > 1 &&
<span className='min'>{t('app.public.store_product_item.minimum_purchase')}{product.quantity_min}</span>
}
{product.amount && {product.amount &&
<div className='price'> <div className='price'>
<p>{FormatLib.price(product.amount)}</p> <p>{FormatLib.price(product.amount)}</p>

View File

@ -181,6 +181,9 @@ export const StoreProduct: React.FC<StoreProductProps> = ({ productSlug, current
</div> </div>
{product.stock.external > 0 && {product.stock.external > 0 &&
<div className='to-cart'> <div className='to-cart'>
{product.quantity_min > 1 &&
<span className='min'>{t('app.public.store_product_item.minimum_purchase')}{product.quantity_min}</span>
}
<FabButton onClick={() => setCount('remove')} icon={<Minus size={16} />} className="minus" /> <FabButton onClick={() => setCount('remove')} icon={<Minus size={16} />} className="minus" />
<input type="number" <input type="number"
value={toCartCount} value={toCartCount}

View File

@ -16,6 +16,7 @@ import { Order } from '../../models/order';
import { AccordionItem } from './accordion-item'; import { AccordionItem } from './accordion-item';
import { StoreListHeader } from './store-list-header'; import { StoreListHeader } from './store-list-header';
import { FabPagination } from '../base/fab-pagination'; import { FabPagination } from '../base/fab-pagination';
import { CaretDoubleDown } from 'phosphor-react';
declare const Application: IApplication; declare const Application: IApplication;
@ -45,6 +46,7 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
const [filterVisible, setFilterVisible] = useState<boolean>(false); const [filterVisible, setFilterVisible] = useState<boolean>(false);
const [machines, setMachines] = useState<checklistOption[]>([]); const [machines, setMachines] = useState<checklistOption[]>([]);
const [accordion, setAccordion] = useState({}); const [accordion, setAccordion] = useState({});
const [filtersPanel, setFiltersPanel] = useState<boolean>(false);
const [pageCount, setPageCount] = useState<number>(0); const [pageCount, setPageCount] = useState<number>(0);
const [currentPage, setCurrentPage] = useState<number>(1); const [currentPage, setCurrentPage] = useState<number>(1);
@ -183,12 +185,20 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
</li> </li>
} }
</ul> </ul>
<aside className='store-filters'> <aside className={`store-filters ${filtersPanel ? '' : 'collapsed'}`}>
<header>
<h3>{t('app.public.store.products.filter')}</h3>
<div className='grpBtn'>
<FabButton onClick={clearAllFilters} className="is-black">{t('app.public.store.products.filter_clear')}</FabButton>
<CaretDoubleDown className='filters-toggle' size={16} weight="bold" onClick={() => setFiltersPanel(!filtersPanel)} />
</div>
</header>
<div className='grp'>
<div className="categories"> <div className="categories">
<header> <header>
<h3>{t('app.public.store.products.filter_categories')}</h3> <h3>{t('app.public.store.products.filter_categories')}</h3>
</header> </header>
<div className="group u-scrollbar"> <div className="list u-scrollbar">
{categoriesTree.map(c => {categoriesTree.map(c =>
<div key={c.parent.id} className={`parent ${activeCategory?.id === c.parent.id || activeCategory?.parent === c.parent.id ? 'is-active' : ''}`}> <div key={c.parent.id} className={`parent ${activeCategory?.id === c.parent.id || activeCategory?.parent === c.parent.id ? 'is-active' : ''}`}>
<p onClick={() => filterCategory(c.parent.id)}> <p onClick={() => filterCategory(c.parent.id)}>
@ -210,12 +220,6 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
</div> </div>
</div> </div>
<div className='filters'> <div className='filters'>
<header>
<h3>{t('app.public.store.products.filter')}</h3>
<div className='grpBtn'>
<FabButton onClick={clearAllFilters} className="is-black">{t('app.public.store.products.filter_clear')}</FabButton>
</div>
</header>
<div className="accordion"> <div className="accordion">
<AccordionItem id={1} <AccordionItem id={1}
isOpen={accordion[1]} isOpen={accordion[1]}
@ -236,6 +240,7 @@ const Store: React.FC<StoreProps> = ({ onError, onSuccess, currentUser }) => {
</AccordionItem> </AccordionItem>
</div> </div>
</div> </div>
</div>
</aside> </aside>
<div className='store-list'> <div className='store-list'>
<StoreListHeader <StoreListHeader

View File

@ -2,35 +2,33 @@
width: 100%; width: 100%;
max-width: 1600px; max-width: 1600px;
margin: 0 auto; margin: 0 auto;
padding-bottom: 6rem;
display: grid; display: grid;
grid-template-columns: repeat(12, minmax(0, 1fr));
grid-template-rows: minmax(0, min-content);
gap: 3.2rem; gap: 3.2rem;
align-items: flex-start; align-items: flex-start;
&-list { &-list {
grid-area: 1 / 1 / 2 / 10;
display: grid; display: grid;
gap: 1.6rem; gap: 1.6rem;
&-item { &-item {
padding: 0.8rem; padding: 0.8rem;
display: grid; display: grid;
grid-auto-flow: column;
grid-template-columns: min-content 1fr;
gap: 1.6rem; gap: 1.6rem;
justify-content: space-between; grid-template-columns: min-content 1fr;
align-items: center; align-items: center;
background-color: var(--gray-soft-lightest); background-color: var(--gray-soft-lightest);
border: 1px solid var(--gray-soft-dark); border: 1px solid var(--gray-soft-dark);
border-radius: var(--border-radius); border-radius: var(--border-radius);
.picture { .picture {
grid-area: 1 / 1 / 2 / 2;
width: 10rem !important; width: 10rem !important;
@include imageRatio(76%); @include imageRatio(76%);
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
.ref { .ref {
grid-area: 1 / 2 / 2 / 3;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
span { span {
@ -43,8 +41,14 @@
margin: 0; margin: 0;
@include text-base(600); @include text-base(600);
} }
.min {
margin-top: 0.8rem;
color: var(--alert);
text-transform: none;
}
} }
.actions { .actions {
grid-area: 2 / 1 / 3 / 3;
align-self: stretch; align-self: stretch;
padding: 0.8rem; padding: 0.8rem;
display: grid; display: grid;
@ -56,7 +60,8 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
.offer { .offer {
align-self: stretch; grid-area: 3 / 1 / 4 / 3;
justify-self: flex-end;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
@ -101,7 +106,6 @@
} }
} }
.group { .group {
grid-area: 2 / 1 / 3 / 10;
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 2.4rem; gap: 2.4rem;
@ -128,7 +132,6 @@
} }
aside { aside {
grid-area: 1 / 10 / 3 / 13;
& > div { & > div {
margin-bottom: 3.2rem; margin-bottom: 3.2rem;
padding: 1.6rem; padding: 1.6rem;
@ -183,4 +186,36 @@
} }
} }
} }
@media (min-width: 1024px) {
&-list-item {
.ref { grid-area: 1 / 2 / 2 / 4; }
.actions { grid-area: 2 / 1 / 3 / 3; }
.offer { grid-area: 2 / 3 / 3 / 4; }
}
}
@media (min-width: 1440px) {
grid-template-columns: repeat(12, minmax(0, 1fr));
grid-template-rows: minmax(0, min-content);
&-list {
grid-area: 1 / 1 / 2 / 10;
&-item {
grid-auto-flow: column;
grid-template-columns: min-content 1fr;
justify-content: space-between;
align-items: center;
.picture { grid-area: auto; }
.ref { grid-area: auto; }
.actions { grid-area: auto; }
.offer {
grid-area: auto;
align-self: flex-start;
}
}
}
.group { grid-area: 2 / 1 / 3 / 10; }
aside { grid-area: 1 / 10 / 3 / 13; }
}
} }

View File

@ -1,33 +1,33 @@
.order-item { .order-item {
width: 100%; width: 100%;
display: flex; display: grid;
gap: 2.4rem; grid-template-rows: repeat(2, min-content);
justify-items: flex-start; grid-template-columns: 2fr 1fr 10ch;
gap: 1.6rem 2.4rem;
align-items: center; align-items: center;
padding: 1.6rem; padding: 1.6rem;
border: 1px solid var(--gray-soft-dark); border: 1px solid var(--gray-soft-dark);
border-radius: var(--border-radius); border-radius: var(--border-radius);
background-color: var(--gray-soft-lightest); background-color: var(--gray-soft-lightest);
& > *:not(button) { flex: 0 1 40%; }
p { margin: 0; } p { margin: 0; }
.ref { .ref {
flex: 1 1 100%; grid-area: 1 / 1 / 2 / 2;
@include text-base(600); @include text-base(600);
} }
.fab-state-label { .fab-state-label {
--status-color: var(--success); --status-color: var(--success);
&.cart { --status-color: var(--secondary-dark); } &.cart { --status-color: var(--information); }
&.paid { --status-color: var(--success-light); } &.paid { --status-color: var(--success); }
&.ready { --status-color: var(--success); } &.ready { --status-color: var(--success); }
&.error { --status-color: var(--alert); } &.error { --status-color: var(--alert); }
&.canceled { --status-color: var(--alert-light); } &.canceled { --status-color: var(--alert-light); }
&.pending { --status-color: var(--information); } &.pending { --status-color: var(--information); }
&.normal { --status-color: var(--success); } &.normal { --status-color: var(--success); }
margin: 0 auto; grid-area: 1 / 2 / 2 / 3;
} }
.status .state-label { margin: 0 auto; }
.client { .client {
grid-area: 2 / 1 / 3 / 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
span { span {
@ -37,6 +37,7 @@
p { @include text-sm; } p { @include text-sm; }
} }
.date { .date {
grid-area: 2 / 2 / 3 / 3;
& > span { & > span {
@include text-xs; @include text-xs;
color: var(--gray-hard-light); color: var(--gray-hard-light);
@ -51,7 +52,7 @@
} }
} }
.price { .price {
flex: 0 1 30%; grid-area: 1 / 3 / 3 / 4;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-self: flex-end; justify-self: flex-end;
@ -61,4 +62,20 @@
} }
p { @include text-base(600); } p { @include text-base(600); }
} }
button { grid-area: 1 / 4 / 3 / 5; }
@media (min-width: 1440px) {
grid-auto-flow: column;
grid-template-rows: auto;
grid-template-columns: 1fr minmax(max-content, 1fr) 2fr 12ch 12ch;
gap: 2.4rem;
.ref,
.fab-state-label,
.client,
.date,
.price,
button { grid-area: auto; }
.fab-state-label { justify-self: center; }
}
} }

View File

@ -3,9 +3,6 @@
max-width: 1600px; max-width: 1600px;
margin: 0 auto; margin: 0 auto;
padding-bottom: 6rem; padding-bottom: 6rem;
@include grid-col(12);
gap: 3.2rem;
align-items: flex-start;
header { header {
@include header(); @include header();
@ -14,13 +11,47 @@
} }
&-list { &-list {
padding-bottom: 6rem;
& > *:not(:first-child) { & > *:not(:first-child) {
margin-top: 1.6rem; margin-top: 1.6rem;
} }
} }
} }
.orders {
display: grid;
grid-template-rows: min-content 8rem 1fr;
align-items: flex-start;
& > header { margin-bottom: 2.4rem; }
.store-filters {
grid-area: 2 / 1 / 4 / 2;
background-color: var(--gray-soft-lightest);
z-index: 1;
}
.store-list { grid-area: 3 / 1 / 4 / 2; }
@media (min-width: 1200px) {
@include grid-col(12);
gap: 2.4rem 3.2rem;
align-items: flex-start;
& > header { margin-bottom: 0; }
.store-filters {
position: static;
grid-area: 2 / 1 / 3 / 4;
}
.store-list { grid-area: 2 / 4 / 3 / -1; }
}
}
.show-order { .show-order {
@include grid-col(12);
gap: 3.2rem;
align-items: flex-start;
&-nav { &-nav {
max-width: 1600px; max-width: 1600px;
margin: 0 auto; margin: 0 auto;

View File

@ -1,6 +1,6 @@
.products-grid { .products-grid {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
gap: 3.2rem; gap: 3.2rem;
.store-product-item { .store-product-item {
@ -16,10 +16,11 @@
display: grid; display: grid;
grid-template-areas: "image image" grid-template-areas: "image image"
"name name" "name name"
"min min"
"price btn" "price btn"
"stock btn"; "stock btn";
grid-template-columns: auto min-content; grid-template-columns: auto min-content;
grid-template-rows: min-content auto min-content min-content; grid-template-rows: repeat(2, min-content) auto repeat(2, min-content);
border: 1px solid var(--gray-soft-dark); border: 1px solid var(--gray-soft-dark);
border-radius: var(--border-radius); border-radius: var(--border-radius);
cursor: pointer; cursor: pointer;
@ -30,11 +31,16 @@
border-radius: var(--border-radius); border-radius: var(--border-radius);
} }
.name { .name {
margin: 2.4rem 0 1.6rem; margin: 1.6rem 0 0.8rem;
grid-area: name; grid-area: name;
align-self: flex-start; align-self: flex-start;
@include text-base(600); @include text-base(600);
} }
.min {
grid-area: min;
@include text-sm;
color: var(--alert);
}
.price { .price {
grid-area: price; grid-area: price;
display: flex; display: flex;

View File

@ -11,8 +11,10 @@
} }
width: 100%; width: 100%;
display: flex; display: grid;
justify-content: space-between; justify-content: space-between;
grid-template-columns: 1fr min-content;
gap: 1.6rem;
align-items: center; align-items: center;
padding: 1.6rem 0.8rem; padding: 1.6rem 0.8rem;
border: 1px solid var(--gray-soft-dark); border: 1px solid var(--gray-soft-dark);
@ -21,8 +23,7 @@
&.out-of-stock { border-color: var(--status-color); } &.out-of-stock { border-color: var(--status-color); }
.itemInfo { .itemInfo {
min-width: 20ch; grid-area: 1 / 1 / 2 / 2;
flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
@ -42,13 +43,12 @@
} }
} }
.details { .details {
grid-area: 2 / 1 / 3 / 3;
display: grid; display: grid;
grid-template-columns: 120px repeat(2, minmax(min-content, 120px)) 120px; grid-template-columns: repeat(4, minmax(min-content, 12ch));
justify-items: center; justify-items: center;
align-items: center; align-items: center;
gap: 1.6rem; gap: 1.6rem;
margin-left: auto;
margin-right: 4rem;
p { p {
margin: 0; margin: 0;
@include text-base(600); @include text-base(600);
@ -68,8 +68,8 @@
justify-self: flex-end; justify-self: flex-end;
} }
} }
.actions { .actions {
grid-area: 1 / 2 / 2 / 3;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
@ -87,5 +87,12 @@
.delete-btn {background: var(--main) } .delete-btn {background: var(--main) }
} }
} }
@media (min-width: 1024px) {
grid-template-columns: 1fr auto min-content;
.itemInfo,
.details,
.actions { grid-area: auto; }
}
} }
} }

View File

@ -4,9 +4,6 @@
max-width: 1600px; max-width: 1600px;
margin: 0 auto; margin: 0 auto;
padding-bottom: 6rem; padding-bottom: 6rem;
@include grid-col(12);
gap: 3.2rem;
align-items: flex-start;
header { header {
@include header(); @include header();
@ -15,8 +12,41 @@
} }
} }
.products {
display: grid;
grid-template-rows: min-content 8rem 1fr;
align-items: flex-start;
& > header { margin-bottom: 2.4rem; }
.store-filters {
grid-area: 2 / 1 / 4 / 2;
background-color: var(--gray-soft-lightest);
z-index: 1;
}
.store-list { grid-area: 3 / 1 / 4 / 2; }
@media (min-width: 1200px) {
@include grid-col(12);
grid-template-rows: min-content 1fr;
gap: 2.4rem 3.2rem;
align-items: flex-start;
& > header { margin-bottom: 0; }
.store-filters {
position: static;
grid-area: 2 / 1 / 3 / 4;
}
.store-list { grid-area: 2 / 4 / 3 / -1; }
}
}
.new-product, .new-product,
.edit-product { .edit-product {
@include grid-col(12);
gap: 3.2rem;
align-items: flex-start;
&-nav { &-nav {
max-width: 1600px; max-width: 1600px;

View File

@ -1,8 +1,41 @@
.store-filters { .store-filters {
grid-column: 1 / 4; margin: 0 -30px;
padding: 0 30px;
box-shadow: 0 10px 10px 0 rgb(39 32 32 / 12%);
.grp {
max-height: 0;
overflow: hidden;
transition: all 500ms ease-in-out;
}
&.collapsed {
header .grpBtn svg { transform: rotateZ(-180deg); }
header .grpBtn button { display: flex; }
.grp {
max-height: 100vh;
padding-bottom: 2.4rem;
}
}
header {
@include header();
margin: 0;
padding: 0 0 2.4rem 0;
.grpBtn {
display: flex;
align-items: center;
button { display: none; }
svg {
cursor: pointer;
transition: transform 250ms ease-in-out;
}
}
}
.categories { .categories {
margin-bottom: 3.2rem; margin-bottom: 1.6rem;
h3 { @include text-base(600); }
.list { .list {
max-height: 30vh; max-height: 30vh;
overflow: auto; overflow: auto;
@ -36,7 +69,6 @@
transition: max-height 500ms ease-in-out; transition: max-height 500ms ease-in-out;
} }
} }
.children { .children {
max-height: 0; max-height: 0;
overflow: hidden; overflow: hidden;
@ -56,11 +88,6 @@
border-top: 1px solid var(--gray-soft-dark); border-top: 1px solid var(--gray-soft-dark);
} }
header {
@include header();
padding: 0 0 2.4rem 0;
}
.accordion { .accordion {
&-item:not(:last-of-type) { &-item:not(:last-of-type) {
margin-bottom: 1.6rem; margin-bottom: 1.6rem;
@ -158,4 +185,13 @@
flex-direction: column; flex-direction: column;
} }
} }
@media (min-width: 1200px) {
margin: 0;
padding: 0 0 2.4rem;
box-shadow: none;
.filters-toggle { display: none; }
.grp { max-height: 100vh; }
header .grpBtn button { display: flex; }
}
} }

View File

@ -1,12 +1,14 @@
.store-list-header { .store-list-header {
padding: 0.8rem 2.4rem; padding: 0.8rem 2.4rem;
display: flex; display: flex;
flex-wrap: wrap;
justify-content: space-between; justify-content: space-between;
background-color: var(--gray-soft); background-color: var(--gray-soft);
border-radius: var(--border-radius); border-radius: var(--border-radius);
p { margin: 0; } p { margin: 0; }
.count { .count {
margin-right: 2.4rem;
display: flex; display: flex;
align-items: center; align-items: center;
p { p {
@ -19,8 +21,14 @@
} }
.display { .display {
width: 100%;
display: flex; display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center; align-items: center;
@media (min-width: 1024px) {
width: auto;
& > *:not(:first-child) { & > *:not(:first-child) {
&::before { &::before {
content: ""; content: "";
@ -30,6 +38,7 @@
background-color: var(--gray-hard-darkest); background-color: var(--gray-hard-darkest);
} }
} }
}
.sort { .sort {
display: flex; display: flex;

View File

@ -1,5 +1,4 @@
.store-list { .store-list {
grid-column: 4 / -1;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
gap: 2.4rem 0; gap: 2.4rem 0;

View File

@ -1,18 +1,14 @@
.store, .store {
.store-product {
max-width: 1600px; max-width: 1600px;
@include grid-col(12);
gap: 2.4rem 3.2rem;
align-items: flex-start;
margin: 0 auto; margin: 0 auto;
padding-bottom: 6rem; padding-bottom: 6rem;
} display: grid;
grid-template-rows: min-content 8rem 1fr;
align-items: flex-start;
.store {
.breadcrumbs { .breadcrumbs {
grid-column: 1 / -1; display: none;
padding: 0.8rem 1.6rem; padding: 0.8rem 1.6rem;
display: flex;
list-style: none; list-style: none;
border-radius: var(--border-radius-sm); border-radius: var(--border-radius-sm);
background-color: var(--gray-soft-light); background-color: var(--gray-soft-light);
@ -31,6 +27,31 @@
color: var(--gray-hard-light); color: var(--gray-hard-light);
cursor: pointer; cursor: pointer;
} }
}
&-filters {
grid-area: 2 / 1 / 4 / 2;
background-color: var(--gray-soft-lightest);
z-index: 1;
}
&-list { grid-area: 3 / 1 / 4 / 2; }
@media (min-width: 768px) {
.breadcrumbs { display: flex; }
}
@media (min-width: 1200px) {
@include grid-col(12);
grid-template-rows: min-content 1fr;
gap: 2.4rem 3.2rem;
align-items: flex-start;
.breadcrumbs { grid-column: 1 / -1; }
&-filters {
position: static;
grid-area: 2 / 1 / 3 / 4;
}
&-list { grid-area: 2 / 4 / 3 / -1; }
} }
} }
@ -39,24 +60,31 @@
&.low { --status-color: var(--alert-light); } &.low { --status-color: var(--alert-light); }
&.out-of-stock { --status-color: var(--alert); } &.out-of-stock { --status-color: var(--alert); }
padding-top: 4rem; max-width: 1600px;
gap: 0 3.2rem; margin: 0 auto;
padding: 4rem 0 6rem;
display: grid;
grid-template-columns: 1fr;
justify-items: flex-start;
align-items: flex-start; align-items: flex-start;
gap: 0 3.2rem;
.ref { .ref {
grid-area: 1 / 1 / 2 / 9; grid-row: 1 / 2;
@include text-sm; @include text-sm;
color: var(--gray-hard-lightest); color: var(--gray-hard-lightest);
text-transform: uppercase; text-transform: uppercase;
} }
.name { .name {
grid-area: 2 / 1 / 3 / 9; grid-row: 2 / 3;
margin: 0.8rem 0 3.2rem; margin: 0.8rem 0 3.2rem;
@include title-lg; @include title-lg;
color: var(--gray-hard-darkest) !important; color: var(--gray-hard-darkest) !important;
} }
.gallery { .gallery {
grid-area: 3 / 1 / 4 / 4; grid-row: 3 / 4;
width: 100%;
max-width: 50rem;
.picture{ .picture{
@include imageRatio; @include imageRatio;
border-radius: var(--border-radius-sm); border-radius: var(--border-radius-sm);
@ -78,7 +106,7 @@
} }
} }
.description { .description {
grid-area: 3 / 4 / 4 / 9; grid-row: 5 / 6;
&-text { &-text {
padding-bottom: 4rem; padding-bottom: 4rem;
overflow: hidden; overflow: hidden;
@ -121,6 +149,7 @@
&-document { &-document {
padding: 2.4rem; padding: 2.4rem;
background-color: var(--gray-soft-light); background-color: var(--gray-soft-light);
border-radius: var(--border-radius-sm);
p { @include text-sm(500); } p { @include text-sm(500); }
.list { .list {
display: flex; display: flex;
@ -135,8 +164,8 @@
} }
} }
aside { aside {
grid-area: 1 / -4 / 4 / -1; margin: 2.4rem 0;
position: sticky; grid-row: 4 / 5;
top: 4rem; top: 4rem;
padding: 4rem; padding: 4rem;
background-color: var(--gray-soft-light); background-color: var(--gray-soft-light);
@ -166,11 +195,20 @@
margin-top: 1.6rem; margin-top: 1.6rem;
padding-top: 3.2rem; padding-top: 3.2rem;
display: grid; display: grid;
grid-template-areas: "minus input plus" grid-template-areas: "min min min"
"minus input plus"
"btn btn btn"; "btn btn btn";
grid-template-columns: repeat(3, minmax(0, min-content)); grid-template-columns: repeat(4, minmax(0, min-content));
justify-content: center;
gap: 1.6rem; gap: 1.6rem;
border-top: 1px solid var(--gray-soft-dark); border-top: 1px solid var(--gray-soft-dark);
.min {
grid-area: min;
display: flex;
justify-content: center;
@include text-sm;
color: var(--alert);
}
.minus { .minus {
grid-area: minus; grid-area: minus;
color: var(--gray-hard-darkest); color: var(--gray-hard-darkest);
@ -189,4 +227,35 @@
} }
} }
} }
@media (min-width: 1024px) {
.ref { grid-area: 1 / 1 / 2 / 3; }
.name { grid-area: 2 / 1 / 3 / 3; }
.gallery { grid-area: 3 / 1 / 4 / 2; }
.description {
margin-top: 2.4rem;
grid-area: 4 / 1 / 5 / 3;
}
aside {
margin: 0;
grid-area: 3 / 2 / 4 / 3;
}
}
@media (min-width: 1200px) {
@include grid-col(12);
grid-template-rows: repeat(2, min-content) 1fr;
align-items: flex-start;
.ref { grid-area: 1 / 1 / 2 / 9; }
.name { grid-area: 2 / 1 / 3 / 9; }
.gallery { grid-area: 3 / 1 / 4 / 4; }
.description { grid-area: 3 / 4 / 4 / 9; }
aside {
grid-area: 1 / 9 / 4 / -1;
position: sticky;
}
}
@media (min-width: 1600px) {
aside { grid-area: 1 / 10 / 4 / -1; }
}
} }

View File

@ -408,6 +408,7 @@ en:
available: "Available" available: "Available"
limited_stock: "Limited stock" limited_stock: "Limited stock"
out_of_stock: "Out of stock" out_of_stock: "Out of stock"
minimum_purchase: "Minimum purchase: "
add: "Add" add: "Add"
add_to_cart: "Add to cart" add_to_cart: "Add to cart"
unit: "unit" unit: "unit"
@ -420,6 +421,7 @@ en:
cart_is_empty: "Your cart is empty" cart_is_empty: "Your cart is empty"
pickup: "Pickup your products" pickup: "Pickup your products"
reference_short: "ref:" reference_short: "ref:"
minimum_purchase: "Minimum purchase: "
unit: "Unit" unit: "Unit"
total: "Total" total: "Total"
checkout_header: "Total amount for your cart" checkout_header: "Total amount for your cart"