Skip to content

Commit 07a85f2

Browse files
committed
Set up exercise 1 - headings and landmarks
1 parent c7e612d commit 07a85f2

File tree

12 files changed

+321
-224
lines changed

12 files changed

+321
-224
lines changed

App.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import EventsPage from "components/page-events"
1313
import PassesPage from "components/page-passes"
1414
import SubmitListingPage from "components/page-submit-listing"
1515
import HikesPage from "components/page-adventures-hikes"
16-
import SemanticsExercise from "./exercise1-headings-landmarks/page-listing-detail"
16+
import Exercise1ListingsPage from "./exercise1-headings-landmarks/page-listings"
17+
import Exercise1ListingPage from "./exercise1-headings-landmarks/page-listing-detail"
1718
import ARIAExercise from "./exercise2-what-is-aria/page-listing-detail"
1819
import A11yNamingExercise from "./exercise3-accessible-names/page-listing-detail"
1920
import A11yNamingExerciseListings from "./exercise3-accessible-names/page-listings"
@@ -36,7 +37,8 @@ export function App() {
3637
<PassesPage path="/passes" />
3738
<HikesPage path="/adventures-hikes" />
3839
<TripIdeasPage path="/trip-ideas" />
39-
<SemanticsExercise path="/exercise1/:id" />
40+
<Exercise1ListingsPage path="/exercise1/listings" />
41+
<Exercise1ListingPage path="/exercise1/:id" />
4042
<ARIAExercise path="/exercise2/:id" />
4143
<A11yNamingExercise path="/exercise3/:id" />
4244
<A11yNamingExerciseListings path="/exercise3/listings" />

components/listing-excerpt.js

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@ import PropTypes from "prop-types"
33
import { Link } from "@reach/router"
44

55
import Icon from "components/icon"
6-
import "./styles/listing.scss"
6+
import "components/styles/listing.scss"
77

88
const ListingExcerpt = ({id, data, image}) => {
99
const { listingName = '', location = '', listingType = '', excerpt = '', amenities = [] } = data
1010
return (
11-
<article className="listing-excerpt">
11+
<div className="listing-excerpt">
1212
<Link to={`/listing/${id}`}>
1313
<img src={image} alt={listingName} />
1414
</Link>
1515
<div>
16-
<header>
16+
<div className="header">
1717
<div>
18-
<h3>{listingName}</h3>
18+
<h1>{listingName}</h1>
1919
<p>{location}{listingType}</p>
2020
</div>
2121
<ul className="amenity-icons">
@@ -25,13 +25,13 @@ const ListingExcerpt = ({id, data, image}) => {
2525
</li>
2626
})}
2727
</ul>
28-
</header>
28+
</div>
2929
<div>
3030
<p>{excerpt}</p>
3131
<p><Link to={`/listing/${id}`} aria-label={`Read more about ${listingName}`}>Read more</Link></p>
3232
</div>
3333
</div>
34-
</article>
34+
</div>
3535
)
3636
}
3737

components/page-listing-detail.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import React from "react"
22
import BodyClassName from "react-body-classname"
33
import sanitizeHtml from "sanitize-html"
44
import {Helmet} from "react-helmet"
5-
import LoadedImageUrl from "./utils/loaded-image-url"
5+
import LoadedImageUrl from "components/utils/loaded-image-url"
66

7-
import "./styles/page-listings.scss"
7+
import "components/styles/page-listings.scss"
88

99
import Icon from "components/icon"
1010
import ListingsData from "data/listings.json"

components/page-listings.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React from "react"
22
import BodyClassName from "react-body-classname"
33
import {Helmet} from "react-helmet"
4-
import LoadedImageUrl from "./utils/loaded-image-url"
4+
import LoadedImageUrl from "components/utils/loaded-image-url"
55

6-
import "./styles/page-listings.scss"
6+
import "components/styles/page-listings.scss"
77

88
import HeaderPortal from "components/header-portal"
99
import ListingsData from "data/listings.json"
@@ -16,11 +16,8 @@ const ListingsPage = () => {
1616
return (
1717
<BodyClassName className="page-listings">
1818
<>
19-
<HeaderPortal>
20-
<h1 className="visually-hidden">Camp Spots</h1>
21-
</HeaderPortal>
2219
<div className="wide-layout listings-header">
23-
<h2>Listings</h2>
20+
<h1>Listings</h1>
2421
<DropdownList defaultItemText="All site types" items={["Campgrounds", "State Parks", "Tent sites", "National Parks"]} />
2522
</div>
2623
<div className="listings-list">

components/styles/listing.scss

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@
99
max-width: 300px;
1010
}
1111

12+
.header,
1213
header {
1314
align-items: flex-start;
1415
display: flex;
1516
margin-bottom: 1em;
1617

17-
h3 {
18+
h1, h2, h3 {
1819
font-size: 1.25rem;
1920
margin: 0;
2021
}

exercise1-headings-landmarks/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The application already has dynamic routing set up for each of the campgrounds l
1818
`data/listings.json`. You can get to the campground listings from "Plan Your Trip >
1919
Find a Camping Spot" in the main navigation, and the individual listing details from there.
2020

21-
Or visit the before and after pages by URL:
21+
Visit the before and after pages by URL:
2222

23-
- http://localhost:1234/workshop3-semantics-aria/listing/listing-cranberry-lake
24-
- http://localhost:1234/workshop3-semantics-aria/exercise1/listing-cranberry-lake
23+
- http://localhost:1234/listing/listing-cranberry-lake
24+
- http://localhost:1234/exercise1/listing-cranberry-lake
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from "react"
2+
import PropTypes from "prop-types"
3+
import { Link } from "@reach/router"
4+
5+
import Icon from "components/icon"
6+
import "components/styles/listing.scss"
7+
8+
const Exercise1ListingExcerpt = ({id, data, image}) => {
9+
const { listingName = '', location = '', listingType = '', excerpt = '', amenities = [] } = data
10+
return (
11+
<article className="listing-excerpt">
12+
<Link to={`/exercise1/${id}`}>
13+
<img src={image} alt={listingName} />
14+
</Link>
15+
<div>
16+
<header>
17+
<div>
18+
<h3>{listingName}</h3>
19+
<p>{location}{listingType}</p>
20+
</div>
21+
<ul className="amenity-icons">
22+
{amenities.map((amenity, index) => {
23+
return <li key={index}>
24+
<Icon name={amenity} />
25+
</li>
26+
})}
27+
</ul>
28+
</header>
29+
<div>
30+
<p>{excerpt}</p>
31+
<p><Link to={`/exercise1/${id}`} aria-label={`Read more about ${listingName}`}>Read more</Link></p>
32+
</div>
33+
</div>
34+
</article>
35+
)
36+
}
37+
38+
Exercise1ListingExcerpt.propTypes = {
39+
id: PropTypes.string,
40+
data: PropTypes.shape({
41+
listingName: PropTypes.string,
42+
location: PropTypes.string,
43+
listingType: PropTypes.string,
44+
imageSrc: PropTypes.string,
45+
excerpt: PropTypes.string,
46+
amenities: PropTypes.array
47+
}),
48+
image: PropTypes.string
49+
}
50+
51+
export default Exercise1ListingExcerpt

exercise1-headings-landmarks/page-listing-detail.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ import Icon from "components/icon"
1111
import ListingsData from "data/listings.json"
1212
import DatePicker from "components/date-picker/date-picker"
1313

14-
import * as imageURLs from "../../images/listings/*.{png,jpg}"
14+
import * as imageURLs from "../images/listings/*.{png,jpg}"
1515

16-
const SemanticsExercise = props => {
16+
const Exercise1ListingPage = props => {
1717
const data = ListingsData.listings[props.id]
1818
const headerImageUrl = LoadedImageUrl(imageURLs, data.detailHeaderImageSrc)
1919
return (
@@ -69,4 +69,4 @@ const SemanticsExercise = props => {
6969
)
7070
}
7171

72-
export default SemanticsExercise
72+
export default Exercise1ListingPage
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import React from "react"
2+
import BodyClassName from "react-body-classname"
3+
import {Helmet} from "react-helmet"
4+
import LoadedImageUrl from "components/utils/loaded-image-url"
5+
6+
import "components/styles/page-listings.scss"
7+
8+
import HeaderPortal from "components/header-portal"
9+
import ListingsData from "data/listings.json"
10+
import ListingExcerpt from "./listing-excerpt"
11+
import DropdownList from "components/dropdown-list"
12+
13+
import * as imageURLs from "../images/listings/*.{png,jpg}"
14+
15+
const Exercise1ListingsPage = () => {
16+
return (
17+
<BodyClassName className="page-listings">
18+
<>
19+
<HeaderPortal>
20+
<h1 className="visually-hidden">Camp Spots</h1>
21+
</HeaderPortal>
22+
<div className="wide-layout listings-header">
23+
<h2>Listings</h2>
24+
<DropdownList defaultItemText="All site types" items={["Campgrounds", "State Parks", "Tent sites", "National Parks"]} />
25+
</div>
26+
<div className="listings-list">
27+
<section className="wide-layout">
28+
{
29+
Object.entries(ListingsData.listings).map((listing, index) => {
30+
const imageUrl = LoadedImageUrl(imageURLs, listing[1].excerptImageSrc)
31+
return (
32+
<ListingExcerpt id={listing[0]} data={listing[1]} image={imageUrl} key={index} />
33+
)
34+
})
35+
}
36+
</section>
37+
</div>
38+
</>
39+
</BodyClassName>
40+
)
41+
}
42+
43+
export default Exercise1ListingsPage

global-styles/forms.scss

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
2+
/* Forms */
3+
.form-field {
4+
position: relative;
5+
}
6+
.form-field .label,
7+
.form-field label {
8+
display: block;
9+
margin-bottom: 0.5em;
10+
font-weight: 500;
11+
font-size: 1rem;
12+
}
13+
.form-field span[class^="icon"] {
14+
background-color: #333;
15+
display: block;
16+
height: 1em;
17+
width: 1em;
18+
}
19+
.form-field .custom-input span[class^="icon"] {
20+
height: 2em;
21+
margin: 1rem 0 0 0.5em;
22+
position: absolute;
23+
}
24+
.form-field span.icon-lookingglass {
25+
background: url(/images/icons/icon-lookingglass.svg) no-repeat;
26+
}
27+
.form-field span.icon-lookingglass-white {
28+
background: url(/images/icons/icon-lookingglass-white.svg) no-repeat;
29+
}
30+
.form-field button.btn-submit span.icon-lookingglass-white {
31+
background-size: contain;
32+
}
33+
.form-field span.icon-calendar {
34+
background: url(/images/icons/icon-calendar.svg) no-repeat;
35+
}
36+
.form-field input,
37+
.form-field textarea {
38+
box-sizing: border-box;
39+
background-color: var(--bgcolor-input);
40+
border-color: var(--color-border-input);
41+
border-radius: 5px;
42+
border-style: solid;
43+
border-width: 1px;
44+
font-family: inherit;
45+
line-height: 2;
46+
width: 100%;
47+
-webkit-appearance: none;
48+
}
49+
.form-field input {
50+
height: 3rem;
51+
padding-left: 3em;
52+
}
53+
.form-field textarea {
54+
height: 10em;
55+
margin-bottom: 1em;
56+
padding: 0.5em 1em;
57+
}
58+
.form-submit [class^='btn-'] {
59+
background-color: var(--color-accent-dark);
60+
border-radius: 5px;
61+
color: var(--color-primary-light);
62+
display: inline-block;
63+
font-weight: bold;
64+
height: 3rem;
65+
line-height: 1;
66+
padding: 0.75rem;
67+
text-align: center;
68+
vertical-align: middle;
69+
min-width: 3em;
70+
}
71+
.form-submit [class^='btn-']:hover {
72+
cursor: pointer;
73+
}
74+
.form-submit .btn-send {
75+
align-items: center;
76+
display: grid;
77+
grid-template-columns: 3fr 1fr;
78+
font-size: 1rem;
79+
width: 6em;
80+
}
81+
.form-submit .btn-lookingglass svg {
82+
display: inline-block;
83+
}
84+
.form-submit .btn-lookingglass svg path {
85+
fill: var(--color-primary-light);
86+
}
87+
.form-submit .icon-arrow {
88+
background: transparent url(/images/icons/icon-right-arrow.svg) no-repeat;
89+
background-size: contain;
90+
display: inline-block;
91+
height: 0.75em;
92+
transition: all 0.25s ease-in-out;
93+
width: 1em;
94+
}
95+
.form-submit .btn-send:hover .icon-arrow {
96+
transform: translateX(4px);
97+
}

0 commit comments

Comments
 (0)