[IMP] point_of_sale, pos_restaurant: convert to scss

This commit converts `pos.css` and `restaurant.css` to use SCSS color
variables. The style of the point of sale application has also been
improved to be more clean and mobile friendly.

task-2954422

closes odoo/odoo#99033

Signed-off-by: Masereel Pierre <pim@odoo.com>
This commit is contained in:
Pierre Masereel
2022-09-08 01:07:42 +02:00
parent e605f90ab6
commit 559536b623
23 changed files with 653 additions and 515 deletions
+7 -1
View File
@@ -106,10 +106,16 @@
],
# This bundle includes the main pos assets.
'point_of_sale.assets': [
'point_of_sale/static/src/scss/pos_variables_extra.scss',
('include', 'web._assets_helpers'),
('include', 'web._assets_backend_helpers'),
('include', 'web._assets_primary_variables'),
'web/static/lib/bootstrap/scss/_functions.scss',
'web/static/lib/bootstrap/scss/_variables.scss',
'web/static/fonts/fonts.scss',
'web/static/src/libs/fontawesome/css/font-awesome.css',
'web/static/lib/daterangepicker/daterangepicker.css',
'point_of_sale/static/src/css/pos.css',
'point_of_sale/static/src/scss/pos.scss',
'point_of_sale/static/src/css/pos_receipts.css',
'point_of_sale/static/src/css/popups/product_info_popup.css',
'point_of_sale/static/src/css/popups/common.css',
@@ -0,0 +1,33 @@
// This file duplicates variables from web_enterprise/static/src/legacy/scss/primary_variables.scss
// to force the colors to use those of Enterprise on Community.
$o-gray-100: #f6f7fa !default;
$o-gray-200: #E0E2E6 !default;
$o-gray-300: #C9CCD2 !default;
$o-gray-400: #9DA1AA !default;
$o-gray-500: #80848F !default;
$o-gray-600: #626774 !default;
$o-gray-700: #4A4F59 !default;
$o-gray-800: #353840 !default;
$o-gray-900: #212529 !default;
$o-enterprise-color: #714B67 !default;
$o-enterprise-primary-color: #017e84 !default;
$o-enterprise-primary-color-light: scale-color($o-enterprise-primary-color, $lightness: 6%) !default;
$o-brand-odoo: $o-enterprise-color !default;
$o-brand-primary: $o-enterprise-primary-color !default;
$o-brand-secondary: #8f8f8f !default;
$o-brand-lightsecondary: $o-gray-100 !default;
$o-list-group-header-color: $o-gray-900 !default;
$o-list-footer-color: $o-gray-900 !default;
$o-list-footer-bg-color: white !default;
$o-btn-secondary-bg: white !default;
$o-btn-secondary-hover-bg: $o-gray-100 !default;
$o-btn-secondary-hover-border: $o-gray-200 !default;
// Duplicate variable from web_enterprise/static/src/webclient/navbar/navbar.variables.scss
$o-navbar-badge-bg: $o-enterprise-primary-color-light !default;
@@ -6,17 +6,14 @@
<div class="pos-receipt-print"></div>
<div class="pos-topheader" t-att-class="{ oe_hidden: state.uiState !== 'READY' }">
<div t-if="tempScreen.isShown" class="block-top-header" />
<div class="pos-branding" t-if= "!env.isMobile">
<img class="pos-logo" t-on-click="() => this.trigger('toggle-debug-widget')"
<div class="pos-branding">
<img t-if="!env.isMobile" class="pos-logo" t-on-click="() => this.trigger('toggle-debug-widget')"
src="/point_of_sale/static/src/img/logo.png" alt="Logo" />
<CashMoveButton t-if="showCashMoveButton()" />
<TicketButton isTicketScreenShown="isTicketScreenShown" />
</div>
<div class="pos-rightheader">
<CashMoveButton t-if="showCashMoveButton() and env.isMobile and !state.mobileSearchBarIsShown" />
<TicketButton isTicketScreenShown="isTicketScreenShown" t-if="env.isMobile and !state.mobileSearchBarIsShown" />
<div class="search-bar-portal search-bar-container sb-product" />
<div class="status-buttons" t-if="state.uiState === 'READY'" t-att-class="{ oe_hidden: state.mobileSearchBarIsShown }">
<div class="status-buttons" t-if="state.uiState === 'READY'">
<CashierName />
<SaleDetailsButton t-if="env.proxy.printer" isHeaderButton="true"/>
<ProxyStatus t-if="env.pos.config.use_proxy" />
@@ -7,20 +7,22 @@
<span class="search-icon" t-if="!env.isMobile"><i class="fa fa-search"></i></span>
<input class="radius-left" t-ref="autofocus" t-att-class="{ 'radius-right': !props.config.filter.show }"
t-model="state.searchInput" t-on-keydown="onSearchInputKeydown" t-on-keyup="onSearchInputKeyup" type="text" t-att-placeholder="props.placeholder" />
<ul t-if="state.showSearchFields and state.searchInput" class="fields">
<t t-foreach="searchFieldsList" t-as="fieldName" t-key="fieldName">
<li t-att-class="{ highlight: fieldName == searchFieldsList[state.selectedSearchFieldId] }"
t-on-click="() => this.trigger('click-search-field', fieldName)">
<span class="field">
<t t-esc="props.config.searchFields.get(fieldName)"></t>
</span>
<span>: </span>
<span class="term">
<t t-esc="state.searchInput"></t>
</span>
</li>
</t>
</ul>
<div t-if="state.showSearchFields and state.searchInput" class="fields">
<ul>
<t t-foreach="searchFieldsList" t-as="fieldName" t-key="fieldName">
<li t-att-class="{ highlight: fieldName == searchFieldsList[state.selectedSearchFieldId] }"
t-on-click="() => this.trigger('click-search-field', fieldName)">
<span class="field">
<t t-esc="props.config.searchFields.get(fieldName)"></t>
</span>
<span>: </span>
<span class="term">
<t t-esc="state.searchInput"></t>
</span>
</li>
</t>
</ul>
</div>
</div>
<div t-if="props.config.filter.show" class="filter radius-right"
t-on-click.stop="() => { state.showFilterOptions = !state.showFilterOptions }">
@@ -13,7 +13,7 @@
</t>
</main>
<footer class="footer">
<div class="button confirm" t-on-click="confirm">
<div class="button confirm highlight" t-on-click="confirm">
Ok
</div>
<div class="button cancel" t-on-click="cancel">
@@ -51,7 +51,7 @@
<div class="button cancel" t-on-mousedown.prevent="cancel">
<t t-esc="props.cancelText" />
</div>
<div class="button confirm" t-on-mousedown.prevent="confirm">
<div class="button confirm highlight" t-on-mousedown.prevent="confirm">
<t t-esc="props.confirmText" />
</div>
</footer>
@@ -7,9 +7,11 @@
<header class="title drag-handle">
<t t-esc="props.title" />
</header>
<textarea t-model="state.inputValue" t-ref="input"></textarea>
<div class="popup-textarea-wrap">
<textarea t-model="state.inputValue" t-ref="input"></textarea>
</div>
<footer class="footer">
<div class="button confirm" t-on-click="confirm">
<div class="button confirm highlight" t-on-click="confirm">
<t t-esc="props.confirmText" />
</div>
<div class="button cancel" t-on-click="cancel">
@@ -13,7 +13,7 @@
<input type="text" t-model="state.inputValue" t-ref="input" />
</div>
<div class="footer">
<div class="button confirm" t-on-click="confirm">
<div class="button confirm highlight" t-on-click="confirm">
<t t-esc="props.confirmText" />
</div>
<div class="button cancel" t-on-click="cancel">
@@ -21,13 +21,13 @@
</td>
<td class="partner-line-email" t-if="!env.isMobile">
<div t-if="props.partner.phone">
<i class="fa fa-phone"/><t t-esc="props.partner.phone"/>
<i class="fa fa-phone fa-fw"/><t t-esc="props.partner.phone"/>
</div>
<div t-if="props.partner.mobile">
<i class="fa fa-mobile fa-lg"/><t t-esc="props.partner.mobile"/>
<i class="fa fa-mobile fa-lg fa-fw"/><t t-esc="props.partner.mobile"/>
</div>
<div t-if="props.partner.email" class="email-field">
<i class="fa fa-paper-plane-o"/><t t-esc="props.partner.email" />
<i class="fa fa-paper-plane-o fa-fw"/><t t-esc="props.partner.email" />
</div>
</td>
<td t-if="env.isMobile">
@@ -11,7 +11,7 @@
<span> Save</span>
</t>
</div>
<div t-if="!state.detailIsShown" class="button new-customer" role="img" aria-label="Add a customer"
<div t-if="!state.detailIsShown" class="button new-customer highlight" role="img" aria-label="Add a customer"
t-on-click="createPartner"
title="Add a customer">
<i t-if="env.isMobile" class="fa fa-plus"/>
@@ -12,11 +12,6 @@
<span class="back_text">Back</span>
</div>
<div class="top-content-center"><h1>Payment</h1></div>
<div class="button next" t-att-class="{ highlight: currentOrder.is_paid() and currentOrder._isValidEmptyOrder() }"
t-on-click="() => this.trigger('validate-order')">
<span class="next_text">Validate</span>
<i class="fa fa-angle-double-right fa-fw"></i>
</div>
</div>
</t>
<div class="main-content">
@@ -27,8 +22,8 @@
</section>
</t>
<div class="paymentmethods-container">
<PaymentScreenPaymentLines paymentLines="paymentLines" />
<div class="paymentmethods">
<p class="title-category">Payment method</p>
<t t-foreach="payment_methods_from_config" t-as="paymentMethod"
t-key="paymentMethod.id">
<div class="button paymentmethod"
@@ -39,9 +34,17 @@
</div>
</t>
</div>
<PaymentScreenPaymentLines paymentLines="paymentLines" />
</div>
<div t-if="!env.isMobile" class="button next validation" t-att-class="{ highlight: currentOrder.is_paid() and currentOrder._isValidEmptyOrder() }"
t-on-click="() => this.trigger('validate-order')">
<div class="pay-circle">
<i class="fa fa-chevron-right" role="img" aria-label="Pay" title="Pay" />
</div>
<span class="next_text">Validate</span>
</div>
</div>
<div class="right-content">
<div class="center-content">
<t t-if="!env.isMobile">
<section class="paymentlines-container">
<PaymentScreenStatus order="currentOrder" />
@@ -52,42 +55,43 @@
<section class="payment-numpad">
<PaymentScreenNumpad />
</section>
<div class="payment-buttons">
<div class="partner-button">
<div class="button" t-att-class="{ highlight: currentOrder.get_partner() }" t-on-click="selectPartner">
<i class="fa fa-user" role="img" title="Customer" />
<t t-set="partner" t-value="currentOrder.get_partner()" />
<span>
<t t-if="partner">
<t t-esc="partner.name" />
</t>
<t t-if="!partner">
Customer
</t>
</span>
</div>
</div>
</div>
<div class="right-content">
<div class="payment-buttons">
<div class="partner-button">
<div class="button" t-att-class="{ highlight: currentOrder.get_partner() }" t-on-click="selectPartner">
<i class="fa fa-user" role="img" title="Customer" />
<t t-set="partner" t-value="currentOrder.get_partner()" />
<span>
<t t-if="partner">
<t t-esc="partner.name" />
</t>
<t t-if="!partner">
Customer
</t>
</span>
</div>
<div class="payment-controls">
<div class="button js_invoice"
t-att-class="{ highlight: currentOrder.is_to_invoice() }"
t-on-click="toggleIsToInvoice">
<i class="fa fa-file-text-o" /> Invoice
</div>
<div t-if="env.pos.config.tip_product_id" class="button js_tip"
t-att-class="{ highlight: currentOrder.get_tip() }"
t-on-click="addTip">
<i class="fa fa-heart" /> Tip <t t-if="currentOrder.get_tip() != 0">(<t t-esc="env.pos.format_currency(currentOrder.get_tip())"/>)</t>
</div>
<div t-if="env.pos.config.iface_cashdrawer" class="button js_cashdrawer"
t-on-click="openCashbox">
<i class="fa fa-archive" /> Open Cashbox
</div>
<div t-if="env.pos.config.ship_later" class="button"
t-att-class="{ highlight: currentOrder.is_to_ship() }"
t-on-click="toggleIsToShip">
<i class="fa fa-clock-o" /> Ship Later
</div>
</div>
<div class="payment-controls">
<div class="button js_invoice"
t-att-class="{ highlight: currentOrder.is_to_invoice() }"
t-on-click="toggleIsToInvoice">
<i class="fa fa-file-text-o" /> Invoice
</div>
<div t-if="env.pos.config.tip_product_id" class="button js_tip"
t-att-class="{ highlight: currentOrder.get_tip() }"
t-on-click="addTip">
<i class="fa fa-heart" /> Tip <t t-if="currentOrder.get_tip() != 0">(<t t-esc="env.pos.format_currency(currentOrder.get_tip())"/>)</t>
</div>
<div t-if="env.pos.config.iface_cashdrawer" class="button js_cashdrawer"
t-on-click="openCashbox">
<i class="fa fa-archive" /> Open Cashbox
</div>
<div t-if="env.pos.config.ship_later" class="button"
t-att-class="{ highlight: currentOrder.is_to_ship() }"
t-on-click="toggleIsToShip">
<i class="fa fa-clock-o" /> Ship Later
</div>
</div>
</div>
@@ -7,17 +7,14 @@
<PSNumpadInputButton value="'2'" />
<PSNumpadInputButton value="'3'" />
<PSNumpadInputButton value="'+10'" changeClassTo="'mode-button'" />
<br />
<PSNumpadInputButton value="'4'" />
<PSNumpadInputButton value="'5'" />
<PSNumpadInputButton value="'6'" />
<PSNumpadInputButton value="'+20'" changeClassTo="'mode-button'" />
<br />
<PSNumpadInputButton value="'7'" />
<PSNumpadInputButton value="'8'" />
<PSNumpadInputButton value="'9'" />
<PSNumpadInputButton value="'+50'" changeClassTo="'mode-button'" />
<br />
<PSNumpadInputButton value="'-'" text="'+/-'" />
<PSNumpadInputButton value="'0'" />
<PSNumpadInputButton value="decimalPoint" />
@@ -3,6 +3,7 @@
<t t-name="PaymentScreenPaymentLines" owl="1">
<div class="paymentlines">
<p class="title-category">Summary</p>
<t t-foreach="props.paymentLines" t-as="line" t-key="line.cid">
<t t-if="line.selected">
<div class="paymentline selected"
@@ -13,7 +13,7 @@
Customer
</t>
</button>
<button class="button pay" t-on-click="() => this.trigger(props.actionToTrigger or 'click-pay')">
<button class="button pay validation" t-on-click="() => this.trigger(props.actionToTrigger or 'click-pay')">
<div class="pay-circle" t-att-class="{ 'highlight': props.isActionButtonHighlighted }">
<i class="fa fa-chevron-right" role="img" aria-label="Pay" title="Pay" />
</div>
@@ -8,7 +8,6 @@
<button class="input-button number-char" t-on-click="() => this.sendInput('3')">3</button>
<button class="mode-button" t-att-class="{'selected-mode': props.activeMode === 'quantity'}"
t-on-click="() => this.changeMode('quantity')">Qty</button>
<br />
<button class="input-button number-char" t-on-click="() => this.sendInput('4')">4</button>
<button class="input-button number-char" t-on-click="() => this.sendInput('5')">5</button>
<button class="input-button number-char" t-on-click="() => this.sendInput('6')">6</button>
@@ -18,7 +17,6 @@
}"
t-att-disabled="!hasManualDiscount"
t-on-click="() => this.changeMode('discount')">% Disc</button>
<br />
<button class="input-button number-char" t-on-click="() => this.sendInput('7')">7</button>
<button class="input-button number-char" t-on-click="() => this.sendInput('8')">8</button>
<button class="input-button number-char" t-on-click="() => this.sendInput('9')">9</button>
@@ -27,7 +25,6 @@
'disabled-mode': !hasPriceControlRights
}" t-att-disabled="!hasPriceControlRights"
t-on-click="() => this.changeMode('price')">Price</button>
<br />
<button class="input-button numpad-minus" t-att-class="{ 'disabled-mode': props.disableSign }" t-on-click="() => this.sendInput('-')">+/-</button>
<button class="input-button number-char" t-on-click="() => this.sendInput('0')">0</button>
<button class="input-button number-char" t-on-click="() => this.sendInput(decimalSeparator)">
@@ -7,17 +7,16 @@
t-att-data-product-id="props.product.id"
t-attf-aria-labelledby="article_product_{{props.product.id}}">
<div class="product-img">
<i role="img" aria-label="Info" title="Info" class="product-info-button fa fa-info-circle"
t-on-click.stop="onProductInfoClick"
/>
<img t-att-src="imageUrl" t-att-alt="props.product.display_name" />
</div>
<div class="product-content">
<div class="product-name" t-attf-id="article_product_{{props.product.id}}">
<t t-esc="props.product.display_name" />
</div>
<span class="price-tag">
<t t-esc="price" />
</span>
</div>
<div class="product-name" t-attf-id="article_product_{{props.product.id}}">
<t t-esc="props.product.display_name" />
</div>
</article>
</t>
@@ -4,10 +4,7 @@
<t t-name="ProductsWidgetControlPanel" owl="1">
<div class="products-widget-control">
<t t-if="!props.hasNoCategories">
<div class="rightpane-header" t-att-class="{
'green-border-bottom': !displayCategImages,
'grey-border-bottom': displayCategImages,
}">
<div class="rightpane-header">
<!-- Breadcrumbs -->
<div class="breadcrumbs">
<span class="breadcrumb">
@@ -17,8 +14,7 @@
</span>
<t t-foreach="props.breadcrumbs" t-as="category" t-key="category.id">
<span class="breadcrumb">
<img src="/point_of_sale/static/src/img/bc-arrow-big.png" class="breadcrumb-arrow"
alt="Slash" />
<i class="breadcrumb-arrow fa fa-caret-right" aria-hidden="true"/>
<span class="breadcrumb-button"
t-on-click="() => this.trigger('switch-category', category.id)">
<t t-esc="category.name"></t>
@@ -35,6 +31,18 @@
</span>
</t>
</div>
<div class="search-bar-container sb-product">
<span t-if="env.isMobile" class="oe_status oe_icon icon" t-on-click="_toggleMobileSearchbar">
<i t-attf-class="fa {{props.mobileSearchBarIsShown ? 'fa-arrow-left' : 'fa-search'}}"/>
</span>
<t t-if="!env.isMobile || props.mobileSearchBarIsShown">
<div class="pos-search-bar">
<i class="fa fa-search" t-on-click="_onPressEnterKey"/>
<input t-ref="search-word-input-product" placeholder="Search Products..." type="text" autofocus="autofocus" t-on-keyup="updateSearch" />
<i class="fa fa-times search-clear-partner" t-on-click="_clearSearch"/>
</div>
</t>
</div>
</div>
<t t-if="props.subcategories.length > 0 and displayCategImages">
<div class="categories">
@@ -48,23 +56,6 @@
</div>
</t>
</t>
<t t-portal="'.pos .pos-topheader .search-bar-container.sb-product'">
<span t-if="env.isMobile" class="oe_status oe_icon icon" t-on-click="_toggleMobileSearchbar">
<i t-attf-class="fa {{props.mobileSearchBarIsShown ? 'fa-arrow-left' : 'fa-search'}}"/>
</span>
<t t-if="!env.isMobile || props.mobileSearchBarIsShown">
<div class="pos-search-bar">
<i class="fa fa-search" t-on-click="_onPressEnterKey"/>
<input t-ref="search-word-input-product" placeholder="Search Products..." type="text" autofocus="autofocus" t-on-keyup="updateSearch" />
<i class="fa fa-times search-clear-partner" t-on-click="_clearSearch"/>
</div>
</t>
</t>
<t t-portal="'.pos .search-database-button'">
<div class="button highlight" t-on-click="_onPressEnterKey">
<i class="fa fa-search"/> Search database
</div>
</t>
</div>
</t>
@@ -10,10 +10,6 @@
<t t-esc="orderAmountPlusTip" />
</h1>
</div>
<div class="button next" t-att-class="{ highlight: !locked }"
t-on-click="orderDone">
New Order <i class="fa fa-angle-double-right"></i>
</div>
</div>
<div class="default-view">
<div class="actions">
@@ -44,6 +40,13 @@
<OrderReceipt order="currentOrder"/>
</div>
</div>
<div class="button next validation" t-att-class="{ highlight: !locked }"
t-on-click="orderDone">
<div class="pay-circle">
<i class="fa fa-chevron-right" role="img" aria-label="Pay" title="Pay" />
</div>
New Order
</div>
</div>
</div>
</t>
@@ -70,8 +70,7 @@
font-weight: normal;
font-size: 80%;
text-align: right;
margin-right: 15px;
margin-left: 15px;
padding: 0 1rem .5rem;
.title {
padding-top: 0.8em;
@@ -86,7 +85,6 @@
.summary {
.loyalty-points {
margin-left: 20px;
float: left;
padding: 10px;
max-width: 216px;
@@ -96,6 +94,10 @@
border-radius: 3px;
}
.loyalty-points-title {
font-size: small;
}
.loyalty-points-spent {
color: #C86E6E;
background: rgba(200, 110, 110, 0.17);
+1 -1
View File
@@ -32,7 +32,7 @@ This module adds several features to the Point of Sale that are specific to rest
'point_of_sale.assets': [
'pos_restaurant/static/lib/**/*.js',
'pos_restaurant/static/src/js/**/*.js',
('after', 'point_of_sale/static/src/css/pos.css', 'pos_restaurant/static/src/css/restaurant.css'),
('after', 'point_of_sale/static/src/scss/pos.scss', 'pos_restaurant/static/src/scss/restaurant.scss'),
],
'web.assets_backend': [
'point_of_sale/static/src/scss/pos_dashboard.scss',
@@ -23,7 +23,7 @@
}
.floor-selector .button {
cursor: pointer;
border-left: dashed 1px rgb(196,196,196);
border-left: solid 1px $gray-400;
-webkit-flex: 1;
flex: 1;
}
@@ -31,7 +31,7 @@
border-left: none;
}
.floor-selector .button.active {
background: #6EC89B;
background: $o-navbar-badge-bg;
color: white;
}
@@ -286,7 +286,7 @@
.pos .order-button.floor-button {
display: flex;
align-items: center;
background: #6EC89B;
background: $o-navbar-badge-bg;
font-weight: bold;
font-size: 16px;
padding-left: 16px;
@@ -345,7 +345,7 @@
margin: 16px;
}
.splitbill-screen.screen .pay-button .button {
background: #e2e2e2;
background: $gray-200;
line-height: 74px;
font-size: 16px;
border: solid 1px rgb(202, 202, 202);
@@ -2,7 +2,7 @@
<templates id="template" xml:space="preserve">
<t t-name="Chrome" t-inherit="point_of_sale.Chrome" t-inherit-mode="extension" owl="1">
<xpath expr="//div[hasclass('search-bar-container')]" position="before">
<xpath expr="//div[hasclass('status-buttons')]" position="before">
<div class="back-to-floor-portal"/>
</xpath>
</t>