Skip to content

Commit

Permalink
Added place link and image attribution tag
Browse files Browse the repository at this point in the history
  • Loading branch information
jesusoterogomez committed Apr 28, 2020
1 parent 48856d2 commit b4e2a30
Show file tree
Hide file tree
Showing 7 changed files with 255 additions and 37 deletions.
42 changes: 25 additions & 17 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import { motion } from "framer-motion";
import { fadeIn } from "Animations";
import CurrentWeather from "components/CurrentWeather";
import PlaceInformation from "components/PlaceInformation";
import { getPlaceData } from "./utils/atlas";
// import { getPlaceData } from "__mocks__/atlas"; // Uncomment when running app through npm start
// import { getPlaceData } from "./utils/atlas";
import { getPlaceData } from "__mocks__/atlas"; // Uncomment when running app through npm start

import "./App.scss";
import ImageAttribution from "components/ImageAttribution";

const App = () => {
const [imageSrc, setImageSrc] = useState<string>();
Expand Down Expand Up @@ -55,31 +56,38 @@ const App = () => {

{/* Display image when fully loaded */}
{imageLoaded && (
<motion.div
initial={true}
className="image-container"
animate={{
opacity: 1,
}}
transition={{ duration: 0.8 }}
style={{
opacity: 0,
backgroundImage: `url(${imageSrc})`,
}}
/>
<>
<motion.div
initial={true}
className="image-container"
animate={{
opacity: 1,
}}
transition={{ duration: 0.8 }}
style={{
opacity: 0,
backgroundImage: `url(${imageSrc})`,
}}
/>
{data && (
<ImageAttribution
attribution={data.image_attribution}
/>
)}
</>
)}

{imageLoaded && data && (
<>
<CurrentWeather />
<PlaceInformation place={data} />

<motion.div
className="gradient-overlay"
initial="hidden"
animate="visible"
variants={fadeIn}
/>

<CurrentWeather />
<PlaceInformation place={data} />
</>
)}
</div>
Expand Down
47 changes: 47 additions & 0 deletions src/components/ImageAttribution/ImageAttribution.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* To rotate text vertically and align it to the bottom of the page
* we rotate the parent container with a right, bottom origin and
* match the right and height property to make the element be aligned
* with the right edge of the page.
*/
.image-attribution {
display: inline-block;
position: absolute;
z-index: 10;

height: 1rem;
right: 1rem;
bottom: 0;

transform: rotate(90deg);
transform-origin: right bottom;
}

/**
* The text is rotated, but we need to flip it so that
* it reads from bottom to top. This is really difficult to do with
* transform and origin properties on the parent, so we just flip
* the child content with the scale property
*/
.image-attribution-link {
transition: opacity 0.3s ease;

opacity: 0.3;
display: block;
position: relative;

right: 14px;
top: 10px;
transform: scale(-1, -1);

color: white;
font-size: 12px;
font-family: "Platform Regular";
text-transform: uppercase;
letter-spacing: 0.12em;
text-decoration: none;

&:hover {
opacity: 1;
}
}
65 changes: 65 additions & 0 deletions src/components/ImageAttribution/ImageAttribution.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from "react";
import { Place } from "Types";
import { motion } from "framer-motion";
import { BASE_URL } from "Constants";
import "./ImageAttribution.scss";

type Props = {
attribution: Place["image_attribution"];
};

const getAttributionLink = (attribution: string) => {
const match = /href="(.+)"/.exec(attribution); // Find link

if (!match) {
return null;
}

// Get link from firt capturing group.
const [, link] = match;

// If the link attribute starts with /users/, prefix it with atlas obscura base URL.
if (/^\/users\//.test(link)) {
return BASE_URL + link;
}

return link;
};

const parseAttribution = (attribution: string) => {
const text = attribution.replace(/<.*?>/g, ""); // Remove all HTML tags

return {
link: getAttributionLink(attribution),
text,
};
};

const ImageAttribution = ({ attribution }: Props) => {
if (!attribution) {
return null;
}

const data = parseAttribution(attribution);

return (
<div className="image-attribution">
<motion.div
initial={true}
animate={{
opacity: 1,
}}
transition={{ duration: 0.8 }}
style={{
opacity: 0,
}}
>
<a className="image-attribution-link" href={data.link || "#"}>
{data.text}
</a>
</motion.div>
</div>
);
};

export default ImageAttribution;
1 change: 1 addition & 0 deletions src/components/ImageAttribution/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./ImageAttribution";
88 changes: 86 additions & 2 deletions src/components/PlaceInformation/PlaceInformation.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
position: absolute;
bottom: 43px;
left: 42px;
width: calc(((100% - 140px) / 12) * 10);
max-width: calc(((100% - 140px) / 12) * 10);
color: white;
text-decoration: none;
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
z-index: 10;

Expand All @@ -30,4 +29,89 @@
font-family: "Freight Pro";
font-size: 22px;
}

&:hover {
.hover-indicator {
opacity: 1;
transform: translateX(0);
}
}
}

// Animations

@mixin animation-pulse($animationName, $color) {
@keyframes #{$animationName} {
0% {
box-shadow: 0 0 0 0 transparentize($color, 0.2);
}
70% {
box-shadow: 0 0 0 10px transparentize($color, 1);
}
100% {
box-shadow: 0 0 8px 0 transparentize($color, 1);
}
}
}

$css-arrow-bg-color: #bd8049;
$css-arrow-color: white;

/**
* Color adjusted from the official atlas obscura brown (#bd8049).
* For better visibility in contrast with background image while still staying "in brand"
*/
$css-arrow-glow-color: #d89962;
@include animation-pulse("button-pulse", $css-arrow-glow-color);

.hover-indicator {
transition: all 0.3s ease;
opacity: 0;
transform: translateX(-16px);
position: relative;
display: inline-block;
height: 0.6em;
width: 0.6em;
background: $css-arrow-bg-color;
border-radius: 50%;
vertical-align: middle;
margin-left: 0.2em;
animation: button-pulse 1.5s infinite;
}

.css-icon-arrow {
height: 3px;
width: 12px;
background: $css-arrow-color;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 4px;

&:before {
content: "";
display: block;
height: 3px;
width: 10px;
background: $css-arrow-color;
position: absolute;
top: -1px;
left: 10px;
transform: translate(-50%, -50%) rotate(45deg);
border-radius: 3px 0px 0px 3px;
}

&:after {
content: "";
display: block;
height: 3px;
width: 10px;
background: $css-arrow-color;
position: absolute;
top: 4px;
left: 10px;
transform: translate(-50%, -50%) rotate(-45deg);
border-radius: 3px 0px 0px 3px;
}
}
26 changes: 16 additions & 10 deletions src/components/PlaceInformation/PlaceInformation.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from "react";
import { Place } from "Types";
import { motion } from "framer-motion";
import "./PlaceInformation.scss";
import { fadeIn, fadeInFromLeft } from "Animations";
import "./PlaceInformation.scss";

type Props = {
place: Place;
Expand All @@ -16,15 +16,21 @@ const PlaceInformation = ({ place }: Props) => {
animate="visible"
variants={fadeIn}
>
<motion.p className="location" variants={fadeInFromLeft}>
{place.location}
</motion.p>
<motion.h1 className="title" variants={fadeInFromLeft}>
{place.title}
</motion.h1>
<motion.h2 className="subtitle" variants={fadeInFromLeft}>
{place.subtitle}
</motion.h2>
<a className="link-unstyled" href={place.url}>
<motion.p className="location" variants={fadeInFromLeft}>
{place.location}
</motion.p>
<motion.h1 className="title" variants={fadeInFromLeft}>
{place.title}

<div className="hover-indicator">
<div className="css-icon-arrow" />
</div>
</motion.h1>
<motion.h2 className="subtitle" variants={fadeInFromLeft}>
{place.subtitle}
</motion.h2>
</a>
</motion.div>
);
};
Expand Down
23 changes: 15 additions & 8 deletions src/index.scss
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
"Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans",
"Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}

.link-unstyled {
text-decoration: none;
color: inherit;
font-size: inherit;
font-family: inherit;
}

0 comments on commit b4e2a30

Please sign in to comment.