Add mobile styling and update base styles for storefront

This commit is contained in:
Nathan Chapman 2022-04-06 19:13:49 -06:00
parent f803491fa3
commit 2e0c0ad83b
25 changed files with 1036 additions and 554 deletions

View File

@ -29,7 +29,7 @@
{% with product=item.product %}
<figure class="item__figure">
<img class="product__image product__image--small" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
<figcaption><strong>{{product.name}}</strong></figcaption>
<figcaption><strong>{{product.name}}</strong><br>Grind: {{item.customer_note}}</figcaption>
</figure>
<span>{{product.sku}}</span>
<span>{{item.quantity}}</span>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@ -9,6 +9,8 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# Add Your Required Allow Host
if DEBUG == False:
ALLOWED_HOSTS = ['ptcoffee-dev.windmillapps.org']
else:
ALLOWED_HOSTS = ['192.168.68.106', '127.0.0.1', 'localhost']
INTERNAL_IPS = [
'127.0.0.1',

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1,6 +1,6 @@
import { getCookie } from "./cookie.js"
let form = document.querySelector('form.order__form')
let form = document.querySelector('form')
// Render the PayPal button into #paypal-button-container
paypal.Buttons({

View File

@ -0,0 +1,12 @@
const gallery = document.querySelectorAll('.gallery__thumbnail')
const productImage = document.querySelector('.product__image')
let currentImg = document.querySelector('.gallery__thumbnail--focus')
gallery.forEach(image => {
image.addEventListener('mouseover', event => {
currentImg.classList.remove('gallery__thumbnail--focus')
event.target.classList.add('gallery__thumbnail--focus')
currentImg = event.target
productImage.src = currentImg.src
})
})

View File

@ -1,9 +1,11 @@
:root {
--fg-color: #34201A;
--bg-color: #f5f5f5;
--bg-alt-color: #eee5d3;
--gray-color: #9d9d9d;
--yellow-color: #f8a911;
--yellow-alt-color: #ffce6f;
--yellow-dark-color: #b27606;
--default-border: 2px solid var(--gray-color);
}
@ -13,17 +15,22 @@ html {
}
body {
background: var(--bg-color);
background-color: var(--bg-color);
font-family: 'Inter', sans-serif;
font-weight: 400;
max-width: 1024px;
padding: 1rem;
padding: 0;
margin: 0 auto;
line-height: 1.75;
color: var(--fg-color);
}
/* ==========================================================================
Typography
========================================================================== */
p {
margin-top: 0;
margin-bottom: 1rem;
}
@ -35,6 +42,7 @@ h1, h2, h3, h4, h5 {
margin: 0;
font-weight: 700;
line-height: 1.3;
margin-bottom: 1rem;
}
h1 {
@ -58,7 +66,7 @@ h5 {
font-size: 1.2rem;
}
small, .text_small {
small, .text-small {
font-size: 0.833rem;
}
@ -67,56 +75,52 @@ small, .text_small {
}
button,
input,
optgroup,
select,
textarea {
color: inherit;
/* ==========================================================================
Tables
========================================================================== */
table {
border-collapse: collapse;
border-spacing: 0;
font: inherit;
margin: 0;
max-width: 100%;
box-sizing: border-box;
width: 100%;
margin-bottom: 1rem;
border: 1px solid var(--gray-color);
}
input {
outline: 0;
}
label {
display: block;
td,
th {
font: inherit;
text-align: left;
font-weight: 700;
font-size: 0.85em;
padding: 2px 10px;
border-bottom: 1px solid;
border-color: var(--gray-color);
}
select {
text-align: left;
border: var(--default-border);
padding: 0.5em;
outline: 0;
th {
font-weight: bold;
}
table a {
white-space: normal;
}
/* ==========================================================================
Forms
========================================================================== */
input[type=text],
input[type=email],
input[type=number],
input[type=date],
input[type=password],
select[multiple=multiple],
select,
textarea {
display: block;
text-align: left;
color: var(--fg-color);
border: var(--default-border);
padding: 0.5rem;
outline: 0;
box-sizing: border-box;
}
input:focus,
@ -125,7 +129,7 @@ textarea:focus {
}
select[multiple=multiple] {
height: 125px;
height: 8rem;
}
@ -145,7 +149,6 @@ input[type=checkbox] + label {
textarea {
width: 100%;
height: 6.25rem;
line-height: 1.45;
}
::-webkit-input-placeholder {
@ -159,36 +162,36 @@ textarea {
}
.action-button,
button,
input[type=submit],
button {
.action-button {
font-family: inherit;
font-weight: bold;
font-size: 1rem;
color: var(--fg-color);
font-size: 1.5rem;
text-decoration: none;
text-transform: lowercase;
font-variant: small-caps;
white-space: nowrap;
color: var(--fg-color);
background-color: var(--yellow-color);
padding: 0.25rem 1rem;
border-radius: 0.2rem;
border: none;
cursor: pointer;
}
button,
input[type=submit]:hover,
.action-button:hover {
background-color: var(--yellow-alt-color);
}
.action-button--large {
font-size: 2rem;
}
form input,
form select {
width: 100%;
box-sizing: border-box;
}
@ -203,10 +206,21 @@ img {
}
/* ==========================================================================
Base Layout
========================================================================== */
.site__header > nav,
main > article,
footer > section {
max-width: 1024px;
padding: 1rem;
margin: 0 auto;
}
/* MODAL MENU */
/* ==========================================================================
Modal
========================================================================== */
.modal-menu {
display: none;
position: fixed; /* Stay in place */
@ -222,16 +236,13 @@ img {
/* Modal Content/Box */
.modal-menu__content {
background-color: #fefefe;
background-color: var(--bg-color);
margin: 25vh auto;
padding: 20px;
border: 1px solid #888;
border: var(--default-border);
max-width: 40rem;
}
.modal-menu__form {
}
.modal-menu__header {
display: flex;
@ -249,118 +260,126 @@ img {
.close-modal:hover,
.close-modal:focus {
color: black;
color: var(--fg-color);
text-decoration: none;
cursor: pointer;
}
.fair_trade--small {
max-width: 4rem;
vertical-align: middle;
/* ==========================================================================
Site
========================================================================== */
.site__ft-stamp {
max-width: 6rem;
}
.product__item {
display: grid;
grid-template-columns: 2fr 1fr;
gap: 0 2rem;
/* Site Header
========================================================================== */
.site__header {
background-color: var(--bg-alt-color);
}
@media (max-width: 876px) {
.product__item {
grid-template-columns: 1fr;
.site__logo > img {
height: 4rem;
}
/* Site Nav
========================================================================== */
.site__nav {
display: flex;
justify-content: space-between;
align-items: center;
}
.site__logo,
.nav__main,
.nav__account {
margin-right: 1rem;
}
@media screen and (max-width: 900px) {
.site__logo,
.nav__main,
.nav__account {
margin-right: 0;
}
.site__nav {
display: grid;
grid-template-columns: 2fr 0.5fr 0.5fr;
gap: 1rem;
}
.site__logo {
grid-column: 1;
}
.nav__main {
grid-column: 1/4;
grid-row: 2;
justify-content: space-between;
}
.nav__account {
grid-column: 2;
grid-row: 1;
}
.site__cart {
grid-column: 3;
grid-row: 1;
}
}
.product__list-item button {
grid-column: 1/3;
align-self: end;
@media screen and (max-width: 400px) {
.site__nav {
grid-template-columns: repeat(2, 1fr);
}
.site__logo {
grid-column: span 2;
justify-self: center;
}
.nav__main {
grid-column: 1/3;
grid-row: 3;
}
.nav__account {
grid-column: 1;
grid-row: 2;
}
.site__cart {
grid-column: 2;
grid-row: 2;
}
}
.product__image {
/*object-fit: cover;*/
max-width: 100%;
}
.product__form {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
}
.product__form input[type=submit] {
/*grid-column: 2;*/
justify-self: end;
}
.site-logo {
height: 4rem;
vertical-align: middle;
}
.site__header div,
.site__header nav {
display: flex;
justify-content: space-between;
align-items: baseline;
}
@media (max-width: 911px) {
.site__header div {
flex-direction: column;
justify-content: center;
}
}
nav a {
text-transform: lowercase;
font-variant: small-caps;
font-weight: bold;
text-decoration: none;
}
nav a:not(:last-child) {
margin-right: 2rem;
}
nav {
margin-bottom: 4rem;
}
.has-menu {
position: relative;
}
.has-menu a {
text-transform: lowercase;
font-variant: small-caps;
font-weight: bold;
text-decoration: none;
}
.has-menu:hover .dropdown-menu {
display: unset;
}
[role="menu"] {
.nav__list {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
[role="menuitem"] {
cursor: pointer;
position: relative;
}
[role="menuitem"]:not(:last-child) {
margin-bottom: 0.5rem;
.nav__menu {
position: relative;
}
.dropdown-menu {
.nav__link {
text-transform: lowercase;
font-variant: small-caps;
font-weight: bold;
text-decoration: none;
white-space: nowrap;
}
.nav__list li:not(:last-child) {
margin-right: 1rem;
}
.nav__list.menu {
flex-direction: column;
}
.nav__dropdown {
list-style: none;
margin: 0;
padding: 0;
background-color: var(--bg-color);
border: var(--default-border);
padding: 0.5rem;
@ -371,220 +390,293 @@ nav {
display: none;
}
.site__copyright {
text-align: center;
}
.keep_calm {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 2rem;
}
.keep_calm__img {
max-width: 250px;
}
@media (max-width: 564px) {
.keep_calm {
grid-template-columns: 1fr;
}
.keep_calm figure {
text-align: center;
@media screen and (max-width: 400px) {
.nav__dropdown {
left: 0;
right: unset;
}
}
.nav__menu:hover .nav__dropdown {
display: flex;
flex-direction: column;
}
/* Site Cart
========================================================================== */
.site__cart {
display: flex;
justify-content: center;
align-items: center;
background-color: var(--yellow-color);
padding: 0 1rem;
justify-self: end;
font-family: inherit;
font-weight: bold;
text-decoration: none;
border-radius: 0.2rem;
text-transform: lowercase;
font-variant: small-caps;
color: var(--fg-color);
background-color: var(--yellow-color);
padding: 0.25rem 1rem;
border-radius: 0.2rem;
cursor: pointer;
margin-left: 2rem;
}
.cart__count {
font-size: 1rem;
}
.cart__icon {
width: 2rem;
height: 2rem;
}
.cart__length {
font-size: 1.5rem;
font-weight: bold;
font-family: 'Inter', sans-serif;
/* ==========================================================================
Articles
========================================================================== */
article > header {
margin-bottom: 1rem;
}
.cart__item {
/* Products
========================================================================== */
.product__list {
display: grid;
grid-template-columns: 1fr 1.5fr;
grid-template-columns: repeat(2, 1fr);
gap: 4rem;
}
.product__item {
text-decoration: none;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
padding: 2rem 0;
border-bottom: 0.05rem solid var(--gray-color);
}
.cart__item:last-child {
.product__item h3 {
text-decoration: underline;
}
@media screen and (max-width: 900px) {
.product__list {
grid-template-columns: 1fr;
gap: 6rem;
}
.product__figure {
grid-row: span 2;
}
}
@media screen and (max-width: 600px) {
.product__item {
grid-template-columns: 1fr;
}
.product__figure {
grid-row: 1;
justify-self: center;
}
}
/* Product Detail
========================================================================== */
.product__detail {
display: grid;
grid-template-columns: 0.25fr 2fr 1fr;
gap: 1rem;
}
.gallery__thumbnail {
border: var(--default-border);
border-color: var(--bg-color);
cursor: pointer;
object-fit: cover;
aspect-ratio: 1/1;
}
.gallery__image {
text-align: center;
}
.gallery__thumbnail--focus {
border-color: var(--yellow-color);
}
.product__form input,
.product__form select {
width: 100%;
}
@media screen and (max-width: 700px) {
.product__detail {
grid-template-columns: 0.25fr 2fr;
}
.product__info {
grid-column: span 2;
}
}
@media screen and (max-width: 700px) {
.product__detail {
grid-template-columns: 1fr;
grid-template-rows: 4rem 1fr auto;
}
.product__gallery {
display: flex;
}
.gallery__thumbnail {
max-height: 4rem;
}
.gallery__thumbnail:not(:last-child) {
margin-right: 0.5rem;
}
.product__image {
max-height: 16rem;
}
.product__info {
grid-column: 1;
}
}
/* Shopping Cart
========================================================================== */
.cart__list {
margin-bottom: 2rem;
border-bottom: none;
}
.cart__item {
padding: 1rem 0;
border-bottom: var(--default-border);
display: grid;
grid-template-columns: 1fr 3fr 1fr;
gap: 1rem;
}
.cart__total_price {
.cart__table-wrapper {
display: flex;
justify-content: flex-end;
}
.cart__summary {
text-align: right;
}
.cart__totals {
width: unset;
font-size: 1.5rem;
}
.cart__total {
.cart__totals th,
.cart__totals td {
border: none;
}
.cart__totals th:first-child,
.cart__totals td:first-child {
text-align: right;
}
.cart__proceed {
text-align: right;
display: flex;
align-items: center;
justify-content: flex-end;
}
.coupon__form {
max-width: 16rem;
align-self: flex-end;
.cart__proceed > .action-button {
font-size: 1.75rem;
}
.item__figure img {
vertical-align: middle;
.item__image {
max-height: 12rem;
}
.item__price {
justify-self: end;
}
.item__form p,
.coupon__form p {
display: flex;
align-items: center;
}
.coupon__form p {
justify-content: flex-end;
}
.item__form input[type=number] {
max-width: 6rem;
}
.coupon__form input[type=text] {
max-width: 8rem;
}
:is(.item__form, .coupon__form) label,
:is(.item__form, .coupon__form) input:not(:last-child) {
margin-right: 0.5rem;
}
@media screen and (max-width: 500px) {
.cart__item {
grid-template-columns: 2fr 1fr;
}
.cart__proceed {
flex-direction: column;
}
.item__info {
grid-column: span 2;
grid-row: 2;
}
.item__price {
grid-column: 2;
grid-row: 1;
}
}
.product__list {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8rem;
/* Checkout / Shipping Address
========================================================================== */
.checkout__address-form input,
.checkout__address-form select {
display: block;
width: 100%;
max-width: 24rem;
}
@media (max-width: 911px) {
.product__list {
grid-template-columns: 1fr;
gap: 4rem;
}
.checkout__address {
margin-bottom: 2rem;
}
.product__list-item {
text-decoration: none;
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 1rem;
}
.product__list-item form {
grid-column: 1/3;
}
.product__list-item figure {
margin: 0;
padding: 0;
#paypal-button-container {
max-width: 24rem;
margin-left: auto;
}
.shipping__details {
margin-bottom: 3rem;
max-width: 32rem;
}
.shipping__details input[type=submit] {
font-size: 1.25rem;
}
.order__total {
/*margin: 3rem 0;*/
text-align: right;
}
/* ==========================================================================
Footer
========================================================================== */
footer {
margin: 4rem 0 0;
box-sizing: border-box;
border-top: var(--default-border);
padding: 2rem 0;
}
.object__header {
display: flex;
align-items: baseline;
justify-content: space-between;
margin-bottom: 1rem;
}
.object__list,
.object__panel {
background-color: white;
border-radius: 0.5rem;
margin-bottom: 2rem;
}
.object__item {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 1rem;
padding: 1rem;
border-bottom: 0.05rem solid var(--gray-color);
text-decoration: none;
align-items: center;
}
.panel__item:last-child,
.object__item:last-child {
border-bottom: unset;
border-radius: 0 0 0.5rem 0.5rem;
}
.object__item:hover {
padding: 1rem 0;
background-color: var(--bg-alt-color);
}
.panel__header {
font-weight: bold;
background-color: var(--bg-alt-color);
border-radius: 0.5rem 0.5rem 0 0;
}
.panel__item {
padding: 1rem;
border-bottom: 0.05rem solid var(--gray-color);
text-decoration: none;
}
.product__detail {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 2rem;
}
.fair-trade-stamp {
footer > section {
text-align: center;
}
.user__emails {
margin-bottom: 4rem;
}
._form_1 {
margin: 0;
}
#_form_62486B0492FDE_ {
margin: 1.7rem 0 !important;
padding: 0 !important;
}

349
src/static/styles/normalize.css vendored Normal file
View File

@ -0,0 +1,349 @@
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
========================================================================== */
/**
* 1. Correct the line height in all browsers.
* 2. Prevent adjustments of font size after orientation changes in iOS.
*/
html {
line-height: 1.15; /* 1 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/* Sections
========================================================================== */
/**
* Remove the margin in all browsers.
*/
body {
margin: 0;
}
/**
* Render the `main` element consistently in IE.
*/
main {
display: block;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/* Grouping content
========================================================================== */
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
pre {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/* Text-level semantics
========================================================================== */
/**
* Remove the gray background on active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* 1. Remove the bottom border in Chrome 57-
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10.
*/
img {
border-style: none;
}
/* Forms
========================================================================== */
/**
* 1. Change the font styles in all browsers.
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
optgroup,
select,
textarea {
font-family: inherit; /* 1 */
font-size: 100%; /* 1 */
line-height: 1.15; /* 1 */
margin: 0; /* 2 */
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* Correct the inability to style clickable types in iOS and Safari.
*/
button,
[type="button"],
[type="reset"],
[type="submit"] {
-webkit-appearance: button;
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Correct the padding in Firefox.
*/
fieldset {
padding: 0.35em 0.75em 0.625em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Remove the default vertical scrollbar in IE 10+.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10.
* 2. Remove the padding in IE 10.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding in Chrome and Safari on macOS.
*/
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}
/* Interactive
========================================================================== */
/*
* Add the correct display in Edge, IE 10+, and Firefox.
*/
details {
display: block;
}
/*
* Add the correct display in all browsers.
*/
summary {
display: list-item;
}
/* Misc
========================================================================== */
/**
* Add the correct display in IE 10+.
*/
template {
display: none;
}
/**
* Add the correct display in IE 10.
*/
[hidden] {
display: none;
}

View File

@ -31,8 +31,8 @@ class AddToCartForm(forms.Form):
(OTHER, 'Other (enter below)')
]
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
grind = forms.ChoiceField(choices=GRIND_CHOICES)
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
class UpdateCartItemForm(forms.Form):
quantity = forms.IntegerField(min_value=1, max_value=20, initial=1)
@ -104,7 +104,7 @@ class OrderCreateForm(forms.ModelForm):
}
class CouponApplyForm(forms.Form):
code = forms.CharField(label='Enter coupon')
code = forms.CharField(label='Coupon code')
class ContactForm(forms.Form):
GOOGLE = 'Google Search'

View File

@ -3,7 +3,7 @@
{% block content %}
<article>
<header class="object__header">
<header>
<h1>About PT Coffee</h1>
</header>
<section>
@ -12,9 +12,7 @@
</figure>
</section>
<section>
<header class="object__header">
<h2>We love coffee!</h2>
</header>
<h2>We love coffee!</h2>
<p><strong>If youve found Port Townsend Coffee Roasting Co., you probably love coffee so much that you seek out the best tasting, Certified Fair Trade Organic coffees available.</strong></p>
<p>Youve probably been around coffee for years, perhaps starting with Specialty Coffees in the 1980s, and know your way around fairly well. How and where coffee is grown and harvested, how its roasted, how to brew it. You value fair, guaranteed wages for growers and sustainable stewardship of the land where its grown.</p>
<p>No matter how much you drink, if youre like us, great coffee is an important perk in your life. You are not alone in this… coffee is the one of the worlds most heavily traded commodities. In addition to the impact it has as a crop on the economies of producing countries, the cafe and coffee house industry touches millions of lives everyday, worldwide, as well.</p>
@ -33,7 +31,7 @@
<p>We roast our coffee much more slowly than most roasters, especially coffee roasters in the Pacific Northwest. The slower roasting process allows for greater bean development. The bean is evenly roasted right to the center and our process mutes some of the acidic compounds, which smooths out the flavor.</p>
<p>Port Townsend Coffee is known for roasts that are darker than others available in the Northwest. Due to our roasting process, which emphasizes patience with the beans as well as air flow adjustments, the darker roasts are smooth and syrupy. Dark roasts from other companies can taste bitter, or slightly burnt due to the size and speed of the roast.</p>
<p>We have been buying beans from the same brokers for many years. They understand the flavor profiles we prefer and seek to accommodate our needs.</p>
<div class="column__layout">
<div>
<h5>Fair Trade and Organic</h5>
<p>We pay a steep premium for these beans, which are typically from smaller farms that are organized into co-ops. These farms take pride in their coffees, as the farmers make a living wage and their families are able to live in a healthier, more secure environment than farmers who grow a conventional coffee crop. The quality of our coffee is consistent, in part due to the quality of organic and fair trade beans.</p>
<h5>Freshness and Storage</h5>

View File

@ -2,14 +2,17 @@
{% block content %}
<article>
<section>
<header>
<p><a href="{% url 'storefront:customer-detail' user.pk %}">&larr; Back</a></p>
<h1>Update Address</h1>
</header>
<section>
<form method="post" action="{% url 'storefront:address-update' customer.pk address.pk %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save changes" class="action-button">
<p>
<input type="submit" value="Save changes">
</p>
</form>
</section>
</article>

View File

@ -2,60 +2,71 @@
{% block content %}
<article>
<section class="object__panel">
<header class="panel__item panel__header">
<h2>Shopping Cart</h2>
</header>
<header>
<h1>Shopping Cart</h1>
</header>
<section class="cart__list">
{% for item in cart %}
<div class="cart__item panel__item">
<div class="cart__item">
{% with product=item.product %}
<figure class="item__figure">
<img class="product__image product__image--small" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
<img class="item__image" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</figure>
<div class="item__details">
<p><strong>{{product.name}}</strong></p>
<p><strong>${{item.price}}</strong></p>
<div class="item__info">
<h4>{{product.name}}</h4>
<p><strong>Grind</strong>: {{item.grind}}</p>
<form class="product__form" action="{% url 'storefront:cart-update' product.pk %}" method="POST">
<form class="item__form" action="{% url 'storefront:cart-update' product.pk %}" method="POST">
{% csrf_token %}
{{ item.update_quantity_form }}
<input type="submit" value="Update">
<p>
{{ item.update_quantity_form }}
<input type="submit" value="Update">
</p>
</form>
<p>
<a href="{% url 'storefront:cart-remove' product.pk %}">Remove from cart</a>
</p>
</div>
<div class="item__price">
<p><strong>${{item.price}}</strong></p>
</div>
{% endwith %}
</div>
{% empty %}
<div class="panel__item">
<div>
<p>No items in cart yet.</p>
</div>
{% endfor %}
</section>
<section class="object__panel">
<header class="panel__item panel__header">
<h4>Cart Totals</h4>
</header>
<div class="panel__item">
<div class="cart__total">
<form action="{% url 'storefront:coupon-apply' %}" method="post" class="coupon__form">
{% csrf_token %}
{{ coupon_apply_form.as_p }}
<p>
<input type="submit" value="Apply" class="action-button">
</p>
</form>
<section class="cart__summary">
<h4>Cart Totals</h4>
<div>
<form class="coupon__form" action="{% url 'storefront:coupon-apply' %}" method="post">
{% csrf_token %}
<p>
{{ coupon_apply_form }}
<input type="submit" value="Apply" class="action-button">
</p>
</form>
<div class="cart__table-wrapper">
<table class="cart__totals">
<tr>
<td>Subtotal</td>
<td>${{cart.get_total_price|floatformat:"2"}}</td>
</tr>
{% if cart.coupon %}
<tr>
<td>Coupon</td>
<td>{{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}</td>
</tr>
{% endif %}
<tr>
<th>Total</th>
<td><strong>${{cart.get_total_price_after_discount|floatformat:"2"}}</strong></td>
</tr>
</table>
</div>
<p class="cart__total_price">
<span class="">Subtotal: ${{cart.get_total_price|floatformat:"2"}}</span><br>
{% if cart.coupon %}
<span class="">Coupon: {{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}</span><br>
{% endif %}
<span><strong>Cart total: ${{cart.get_total_price_after_discount|floatformat:"2"}}</strong></span>
</p>
<p class="cart__total">
<a href="{% url 'storefront:product-list' %}">Continue Shopping</a>{% if cart|length > 0 %}&emsp;or&emsp;<a class="action-button action-button--large" href="{% url 'storefront:checkout-address' %}">Proceed to Checkout</a>{% endif %}
<p class="cart__proceed">
<a href="{% url 'storefront:product-list' %}">Continue Shopping</a>{% if cart|length > 0 %}&emsp;or&emsp;<a class="action-button" href="{% url 'storefront:checkout-address' %}">Proceed to Checkout</a>{% endif %}
</p>
</div>
</section>

View File

@ -3,18 +3,18 @@
{% block content %}
<article>
<header class="object__header">
<h2>Checkout</h2>
<header>
<h1>Checkout</h1>
</header>
<section class="order__shipping object__panel">
<div class="shipping__details panel__item">
<h3>Shipping Address</h3>
<form action="" method="POST" class="address__form">
{% csrf_token %}
{{form.as_p}}
<section>
<h3>Shipping Address</h3>
<form class="checkout__address-form" action="" method="POST">
{% csrf_token %}
{{form.as_p}}
<p>
<input type="submit" value="Continue to Payment">
</form>
</div>
</p>
</form>
</section>
</article>
{% endblock %}

View File

@ -1,17 +0,0 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<article>
<h2>Checkout</h2>
<section class="order__details">
<div class="order__shipping">
<h3>Shipping Method</h3>
<form action="post" class="address__form">
{{form.as_p}}
<input type="submit" value="Review order">
</form>
</div>
</section>
</article>
{% endblock %}

View File

@ -2,12 +2,16 @@
{% block content %}
<article>
<h1>Contact PT Coffee</h1>
<header>
<h1>Contact us</h1>
</header>
<section>
<form action="{% url 'storefront:contact' %}" method="post">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Send message">
<p>
<input type="submit" value="Send message">
</p>
</form>
</section>
</article>

View File

@ -3,20 +3,18 @@
{% block content %}
<article>
<header class="object__header">
<header>
<h1>{{customer.get_full_name}}</h1>
<a href="{% url 'storefront:customer-update' customer.pk %}" class="action-button">Edit profile</a>
</header>
<section class="object__panel">
<div class="object__item panel__header">
<h4>Info</h4>
</div>
<div class="panel__item">
<section>
<h4>Info</h4>
<div>
<strong>Email address</strong><br>
{{customer.email}}<br>
<a href="{% url 'account_email' %}">Manage</a>
</div>
<div class="panel__item">
<div>
<strong>Default shipping address</strong><br>
{% with shipping_address=customer.default_shipping_address %}
<address>
@ -30,7 +28,7 @@
</address>
{% endwith %}
</div>
<div class="panel__item">
<div>
<p><strong>All addresses</strong></p>
{% for address in customer.addresses.all %}
<p>
@ -51,24 +49,29 @@
</div>
</section>
{% with order_list=customer.orders.all %}
<header class="object__header">
<h3>Your orders</h3>
</header>
<section class="object__list">
<div class="object__item panel__header object__item--col3" href="order-detail">
<span>Order #</span>
<span>Date</span>
<span>Total</span>
</div>
{% for order in order_list %}
<a class="object__item object__item--col3" href="{% url 'storefront:order-detail' customer.pk order.pk %}">
<span>#{{order.pk}}</span>
<span>{{order.created_at|date:"M j, Y"}}</span>
<span>${{order.total_net_amount}}</span>
</a>
{% empty %}
<span class="object__item">No orders</span>
{% endfor %}
<section>
<table>
<thead>
<tr>
<th>Order #</th>
<th>Date</th>
<th colspan="2">Total</th>
</tr>
</thead>
<tbody>
{% for order in order_list %}
<tr>
<td>#{{order.pk}}</td>
<td>{{order.created_at|date:"M j, Y"}}</td>
<td>${{order.total_net_amount}}</td>
<td><a href="{% url 'storefront:order-detail' customer.pk order.pk %}">See details &rarr;</a></td>
</tr>
{% empty %}
<span class="object__item">No orders</span>
{% endfor %}
</tbody>
</table>
</section>
{% endwith %}
</article>

View File

@ -1,15 +1,17 @@
{% extends "base.html" %}
{% block content %}
<article class="product">
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">&larr; Back</a></p>
<h1>Update your profile</h1>
<article>
<header>
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">&larr; Back</a></p>
<h1>Update your profile</h1>
</header>
<section>
<form method="POST" action="{% url 'storefront:customer-update' customer.pk %}">
{% csrf_token %}
{{form.as_p}}
<p class="form__submit">
<input class="action-button" type="submit" value="Save changes">
<p>
<input type="submit" value="Save changes">
</p>
</form>
</section>

View File

@ -4,47 +4,60 @@
{% block content %}
<article>
<p><a href="{% url 'storefront:customer-detail' customer.pk %}">&larr; Back</a></p>
<header class="object__header">
<h1><img src="{% static 'images/box.png' %}" alt=""> Order #{{order.pk}}</h1>
<header>
<h1>Order #{{order.pk}}</h1>
<h3>Placed on {{order.created_at|date:"M j, Y"}}</h3>
</header>
<section class="object__list">
<div class="object__item panel__header object__item--col5">
<span>Product</span>
<span></span>
<span>Quantity</span>
<span>Price</span>
<span>Total</span>
</div>
{% for item in order.lines.all %}
<div class="object__item object__item--col5">
{% with product=item.product %}
<figure class="item__figure">
<img class="product__image product__image--small" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</figure>
<span><strong>{{product.name}}</strong></span>
<span>{{item.quantity}}</span>
<span>${{product.price}}</span>
<span>${{item.get_total}}</span>
{% endwith %}
</div>
{% empty %}
<p class="object__item">No items in order yet.</p>
{% endfor %}
<section>
<table>
<thead>
<tr>
<th colspan="2">Product</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{% for item in order.lines.all %}
<tr>
{% with product=item.product %}
<td>
<img src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</td>
<td><strong>{{product.name}}</strong></td>
<td>{{item.quantity}}</td>
<td>${{product.price}}</td>
<td>${{item.get_total}}</td>
{% endwith %}
</tr>
{% empty %}
<tr>
<td colspan="5">No items in order</td>
</tr>
{% endfor %}
</tbody>
</table>
</section>
<section class="object__panel">
<div class="object__item panel__header">
<h4>Payment</h4>
</div>
<div class="panel__item">
<p>
<span>Subtotal: {{order.total_net_amount}}</span><br>
{% if order.coupon %}
<span>Discount: {{order.coupon.discount_value}} {{order.coupon.get_discount_value_type_display}}</span><br>
{% endif %}
<strong>Total: {{order.get_total_price_after_discount}}</strong>
</p>
</div>
<section>
<h4>Payment</h4>
<table>
<tr>
<td>Subtotal</td>
<td>${{order.total_net_amount}}</td>
</tr>
{% if order.coupon %}
<tr>
<td>Discount</td>
<td>{{order.coupon.discount_value}} {{order.coupon.get_discount_value_type_display}}</td>
</tr>
{% endif %}
<tr>
<th>Total</th>
<td><strong>${{order.get_total_price_after_discount}}</strong></td>
</tr>
</table>
</section>
</article>
{% endblock content %}

View File

@ -2,63 +2,73 @@
{% load static %}
{% block head %}
<script defer src="https://www.paypal.com/sdk/js?client-id=AVELl5svEDTPo3FRNViyjWnqODfFsAHbKKdm5BlwpKCwZCVxTraFF9Ax3N1xlkoEWSpOj7AI_T9xYMRu&currency=USD"></script>
<script defer src="https://www.paypal.com/sdk/js?client-id={{PAYPAL_CLIENT_ID}}&currency=USD"></script>
<script type="module" defer src="{% static 'scripts/payment.js' %}"></script>
{% endblock %}
{% block content %}
<article>
<header class="object__header">
<h2>Checkout</h2>
<header>
<h1>Checkout</h1>
</header>
<section class="object__panel">
<div class="order__shipping panel__item">
<h3>Shipping Address</h3>
<address>
{{shipping_address.first_name}}
{{shipping_address.last_name}}<br>
{{shipping_address.street_address_1}}<br>
{% if shipping_address.street_address_2 %}
{{shipping_address.street_address_2}}<br>
{% endif %}
{{shipping_address.city}}, {{shipping_address.state}}, {{shipping_address.postal_code}}
</address>
<a class="action-button" href="{% url 'storefront:checkout-address' %}">edit</a>
</div>
<div class="order__list panel__item">
<h3>Cart Summary</h3>
{% for item in cart %}
<div class="cart__item">
{% with product=item.product %}
<figure class="item__figure">
<img class="product__image product__image--small" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</figure>
<div class="item__details">
<p><strong>{{product.name}}</strong></p>
<p><strong>${{item.price}}</strong></p>
<p><strong>Quantity</strong>: {{item.quantity}}</p>
<p><strong>Grind options</strong>: {{item.grind}}</p>
</div>
{% endwith %}
<section class="checkout__address">
<h3>Shipping address</h3>
<address>
{{shipping_address.first_name}}
{{shipping_address.last_name}}<br>
{{shipping_address.street_address_1}}<br>
{% if shipping_address.street_address_2 %}
{{shipping_address.street_address_2}}<br>
{% endif %}
{{shipping_address.city}}, {{shipping_address.state}}, {{shipping_address.postal_code}}
</address>
<a class="action-button" href="{% url 'storefront:checkout-address' %}">Change</a>
</section>
<section class="cart__list">
<h3>Review items</h3>
{% for item in cart %}
<div class="cart__item">
{% with product=item.product %}
<figure>
<img src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</figure>
<div>
<h4>{{product.name}}</h4>
<p><strong>Grind options</strong>: {{item.grind}}</p>
<p><strong>Quantity</strong>: {{item.quantity}}</p>
</div>
{% endfor %}
<div class="item__price">
<p><strong>${{item.price}}</strong></p>
</div>
{% endwith %}
</div>
<div class="order__total panel__item">
<h3>Order Totals</h3>
<form action="" method="POST" class="order__form">
{% csrf_token %}
{{form.as_p}}
{# <input type="submit" value="Place order"> #}
</form>
<p class="cart__total_price">
<span class="">Subtotal: ${{cart.get_total_price|floatformat:"2"}}</span><br>
{% endfor %}
</section>
<section class="cart__summary">
<h3>Order summary</h3>
<form action="" method="POST">
{% csrf_token %}
{{form.as_p}}
</form>
<div class="cart__table-wrapper">
<table class="cart__totals">
<tr>
<td>Subtotal</td>
<td>${{cart.get_total_price|floatformat:"2"}}</td>
</tr>
{% if cart.coupon %}
<span class="">Coupon: {{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}</span><br>
<tr>
<td>Coupon</td>
<td>{{cart.coupon.discount_value}} {{cart.coupon.get_discount_value_type_display}}</td>
</tr>
{% endif %}
<span class="cart__total_price">Cart total: <strong>${{cart.get_total_price_after_discount|floatformat:"2"}}</strong></span>
</p>
<div id="paypal-button-container"></div>
<tr>
<th>Total</th>
<td><strong>${{cart.get_total_price_after_discount|floatformat:"2"}}</strong></td>
</tr>
</table>
</div>
<div id="paypal-button-container"></div>
</section>
</article>
{% endblock %}

View File

@ -2,25 +2,30 @@
{% load static %}
{% block head %}
<script defer src="{% static 'scripts/product_form.js' %}"></script>
<script defer src="{% static 'scripts/product_gallery.js' %}"></script>
{% endblock %}
{% block content %}
<article class="product__item">
<figure class="product__figure">
<img class="product__image" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
<article class="product__detail">
<section class="product__gallery">
{% for photo in product.productphoto_set.all %}
<img class="gallery__thumbnail {% if forloop.first %}gallery__thumbnail--focus{% endif %}" src="{{ photo.image.url }}" alt="{{ photo }}">
{% endfor %}
</section>
<figure class="gallery__image">
<img class="product__image" src="{{ product.productphoto_set.first.image.url }}" alt="{{ product.name }}">
</figure>
<section>
<section class="product__info">
<h1>{{product.name}}</h1>
<p>{{product.description}}</p>
<p class="fair-trade-stamp"><img class="fair_trade--small" src="{% static 'images/fair_trade_stamp.png' %}" alt=""></p>
<p class="site__ft-stamp"><img class="fair_trade--small" src="{% static 'images/fair_trade_stamp.png' %}" alt=""></p>
<p>$<strong>{{product.price}}</strong></p>
<p>{{product.weight.oz}} oz</p>
<form method="post" action="{% url 'storefront:cart-add' product.pk %}">
<form class="product__form" method="post" action="{% url 'storefront:cart-add' product.pk %}">
{% csrf_token %}
{{ form.as_p }}
<p>
<input type="submit" value="Add to cart" class="action-button">
<input type="submit" value="Add to cart">
</p>
</form>
</section>

View File

@ -2,19 +2,20 @@
{% block content %}
<article>
<header>
<h1>Coffee</h1>
</header>
<section class="product__list">
{% for product in product_list %}
<a href="{% url 'storefront:product-detail' product.pk %}" class="product__list-item">
<a class="product__item" href="{% url 'storefront:product-detail' product.pk %}">
<figure class="product__figure">
<img class="product__image" src="{{product.productphoto_set.first.image.url}}" alt="{{product.productphoto_set.first.image}}">
</figure>
<div>
<h3>{{ product.name }}</h3>
<p>{{product.description}}</p>
<p>$<strong>{{product.price}}</strong></p>
<p>{{product.weight.oz}} oz</p>
<p>{{product.description|truncatewords:20}}</p>
<p>$<strong>{{product.price}}</strong> | {{product.weight.oz}} oz</p>
</div>
<button class="action-button">View product</button>
</a>
{% endfor %}
</section>

View File

@ -203,6 +203,7 @@ class OrderCreateView(CreateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['shipping_address'] = self.request.session.get('shipping_address')
context['PAYPAL_CLIENT_ID'] = settings.PAYPAL_CLIENT_ID
return context
def form_valid(self, form):

View File

@ -14,6 +14,7 @@
<link href="https://fonts.googleapis.com/css2?family=Eczar:wght@400;700&family=Inter:wght@100;400;700&display=swap" rel="stylesheet">
{% compress css %}
<link rel="stylesheet" type="text/css" href="{% static "styles/normalize.css" %}">
<link rel="stylesheet" type="text/css" href="{% static "styles/main.css" %}">
{% endcompress %}
@ -37,61 +38,53 @@
</div>
<header class="site__header">
<div>
<a href="{% url 'storefront:product-list' %}"><img class="site-logo" src="{% static 'images/site_logo.svg' %}" alt=""></a>
<nav>
<a href="{% url 'storefront:product-list' %}">Shop</a>
<a href="">Cafe</a>
<a href="">Fair Trade</a>
<a href="{% url 'storefront:about' %}">About</a>
<a href="{% url 'storefront:contact' %}">Contact</a>
</nav>
<div>
{% if user.is_authenticated %}
<div class="has-menu">
<a href="{% url 'storefront:customer-detail' user.pk %}">Account ▼</a>
<ul role="menu" class="dropdown-menu">
{% if user.is_staff %}
<li role="menuitem"><a href="{% url 'dashboard:home' %}">Dashboard</a></li>
{% endif %}
<li role="menuitem"><a href="{% url 'storefront:customer-detail' user.pk %}">Orders</a></li>
<li role="menuitem"><a href="{% url 'account_logout' %}">Log Out</a></li>
</ul>
</div>
{% else %}
<span>
<a href="{% url 'account_login' %}">Log In</a>&emsp;|&emsp;<a href="{% url 'account_signup' %}">Sign Up</a>
</span>
{% endif %}
<a class="site__cart" href="{% url 'storefront:cart-detail' %}">
<span class="cart__length">{{cart|length}}</span>
<img class="cart__icon" src="{% static 'images/shopping_cart.svg' %}" alt="Shopping cart">
</a>
<nav class="site__nav">
<a class="site__logo" href="{% url 'storefront:product-list' %}"><img src="{% static 'images/site_logo.svg' %}" alt="Port Townsend Roasting Co."></a>
<ul class="nav__list nav__main">
<li><a class="nav__link" href="{% url 'storefront:product-list' %}">Shop</a></li>
<li><a class="nav__link" href="">Cafe</a></li>
<li><a class="nav__link" href="">Fair trade</a></li>
<li><a class="nav__link" href="{% url 'storefront:about' %}">About</a></li>
<li><a class="nav__link" href="{% url 'storefront:contact' %}">Contact</a></li>
</ul>
{% if user.is_authenticated %}
<div class="nav__menu nav__account">
<a class="nav__link" href="{% url 'storefront:customer-detail' user.pk %}">Account ▼</a>
<ul class="nav__dropdown">
{% if user.is_staff %}
<li><a class="nav__link" href="{% url 'dashboard:home' %}">Dashboard</a></li>
{% endif %}
<li><a class="nav__link" href="{% url 'storefront:customer-detail' user.pk %}">Orders</a></li>
<li><a class="nav__link" href="{% url 'account_logout' %}">Logout</a></li>
</ul>
</div>
</div>
{% else %}
<ul class="nav__list nav__account">
<li><a class="nav__link" href="{% url 'account_login' %}">Login</a></li>
<li>/</li>
<li><a class="nav__link" href="{% url 'account_signup' %}">Signup</a></li>
</ul>
{% endif %}
<a class="site__cart" href="{% url 'storefront:cart-detail' %}">
<span class="cart__count">{{cart|length}}</span>
<img class="cart__icon" src="{% static 'images/shopping_cart.svg' %}" alt="Shopping cart">
</a>
</nav>
</header>
<main>
{% block content %}
{% endblock content %}
</main>
<footer>
<div class="keep_calm">
<figure>
<img class="keep_calm__img" src="{% static 'images/keep_calm.jpg' %}" alt="Keep calm and drink coffee">
</figure>
<div>
<h4>Problem with your order?<br>Have a question?</h4>
<p>Please contact us, were happy to help you over the phone at <a href="tel:+13603855856">(360) 385-5856</a> between 8:00 am and 10:00 pm Pacific Time.</p>
<div class="_form_1"></div><script src="https://ptcoffee.activehosted.com/f/embed.php?id=1" type="text/javascript" charset="utf-8"></script>
</div>
</div>
<div class="site__copyright">
<section>
<p>
<small>Copyright © 2016-{% now "Y" %} Better Living Food Company Inc.</small><br>
<small>Fair Trade&nbsp;|&nbsp;Organic&nbsp;|&nbsp;Port Townsend, WA 98368</small><br><br>
<img src="{% static 'images/fair_trade_stamp.png' %}" alt="">
<img class="site__ft-stamp" src="{% static 'images/fair_trade_stamp.png' %}" alt="">
</p>
</div>
</section>
</footer>
<script src="https://ptcoffee.activehosted.com/f/embed.php?id=1" type="text/javascript" charset="utf-8"></script>
</body>
</html>