Skip to content

Commit c83447b

Browse files
committed
add twitter routes, some animation fixes
1 parent 1307c76 commit c83447b

File tree

10 files changed

+260
-112
lines changed

10 files changed

+260
-112
lines changed

now.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
"alias": "swiip.now.sh",
66
"env": {
77
"GITHUB_API_TOKEN": "@github-api-token",
8-
"CONTENTFUL_API_TOKEN": "@contentful-api-token"
8+
"CONTENTFUL_API_TOKEN": "@contentful-api-token",
9+
"TWITTER_CONSUMER_KEY": "@twitter-consumer-key",
10+
"TWITTER_CONSUMER_SECRET": "@twitter-consumer-secret",
11+
"TWITTER_ACCESS_TOKEN": "@twitter-access-token",
12+
"TWITTER_ACCESS_TOKEN_SECRET": "@twitter-access-token-secret"
913
},
1014
"routes": [
1115
{ "src": "/api/(.*)", "dest": "packages/server/$1.js" },
+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import html from "../html";
2+
import style from "../style";
3+
4+
import { cascading, bounceInRight, outLeft } from "./animations";
5+
6+
const CardContainer = style("section")(({ exiting }) =>
7+
cascading(
8+
{
9+
display: "flex",
10+
flexDirection: "column",
11+
justifyContent: "center",
12+
alignItems: "center",
13+
opacity: "0",
14+
animation: exiting
15+
? `${outLeft} .3s forwards`
16+
: `${bounceInRight} .3s forwards`,
17+
height: "100%",
18+
flex: "0 0 300px"
19+
},
20+
0
21+
)
22+
);
23+
24+
const ImageContainer = style("div")({
25+
padding: "20px",
26+
width: "300px",
27+
height: "200px"
28+
});
29+
30+
const ImageBox = style("div")({
31+
width: "100%",
32+
height: "100%",
33+
overflow: "hidden"
34+
});
35+
36+
const Image = style("img")({
37+
width: "100%",
38+
height: "100%",
39+
objectFit: "cover",
40+
transition: "transform .3s"
41+
});
42+
43+
const Break = style("hr")({
44+
width: "95%",
45+
opacity: ".3",
46+
transition: "opacity .3s"
47+
});
48+
49+
const Title = style("h3")(({ show }) => ({
50+
display: show ? "block" : "none",
51+
padding: "20px",
52+
margin: "0",
53+
height: "100px",
54+
fontWeight: "normal",
55+
textAlign: "center",
56+
transition: "transform .3s"
57+
}));
58+
59+
const Description = style("p")(({ noTitle }) => ({
60+
padding: "20px",
61+
margin: "0",
62+
height: noTitle ? "200px" : "100px",
63+
fontSize: "16px",
64+
opacity: noTitle ? "1" : "0.5"
65+
}));
66+
67+
const ClickZone = style("a")({
68+
margin: "0",
69+
":hover img": {
70+
transform: "scale(1.2)"
71+
},
72+
":hover hr": {
73+
opacity: "1"
74+
},
75+
":hover h3": {
76+
transform: "scale(1.2)"
77+
}
78+
});
79+
80+
const Card = ({ title, image, link, description, exiting }) => html`
81+
<${CardContainer} exiting=${exiting}>
82+
<${ClickZone} href=${link} target="_blank" draggable=${false}>
83+
<${ImageContainer}>
84+
<${ImageBox}>
85+
<${Image} src=${image} alt=${title} draggable=${false} />
86+
<//>
87+
<//>
88+
<${Break} />
89+
<${Title} draggable=${false} show=${title !== null}>${title}<//>
90+
<${Description} draggable=${false} noTitle=${title === null}>
91+
${description}
92+
<//>
93+
<//>
94+
<//>
95+
`;
96+
97+
export default Card;
+20-97
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import { useState, useRef } from "preact/hooks";
1+
import { useState, useRef, useEffect } from "preact/hooks";
22

33
import html from "../html";
44
import style from "../style";
55

6-
import { cascading, bounceInRight, outLeft, spin } from "./animations";
6+
import { spin } from "./animations";
77

88
const CardsContainer = style("article")({
99
height: "100%",
@@ -31,122 +31,45 @@ const Arrow = style("button")(({ show }) => ({
3131
}
3232
}));
3333

34-
const CardContainer = style("section")(({ exiting }) =>
35-
cascading(
36-
{
37-
display: "flex",
38-
flexDirection: "column",
39-
justifyContent: "center",
40-
alignItems: "center",
41-
opacity: "0",
42-
animation: exiting
43-
? `${outLeft} .3s forwards`
44-
: `${bounceInRight} .3s forwards`,
45-
height: "100%",
46-
flex: "0 0 300px"
47-
},
48-
0
49-
)
50-
);
51-
52-
const ImageContainer = style("div")({
53-
padding: "20px",
54-
width: "300px",
55-
height: "200px"
56-
});
57-
58-
const ImageBox = style("div")({
59-
width: "100%",
60-
height: "100%",
61-
overflow: "hidden"
62-
});
63-
64-
const Image = style("img")({
65-
width: "100%",
66-
height: "100%",
67-
objectFit: "cover",
68-
transition: "transform .3s"
69-
});
70-
71-
const Break = style("hr")({
72-
width: "95%",
73-
opacity: ".3",
74-
transition: "opacity .3s"
75-
});
76-
77-
const Title = style("h3")({
78-
padding: "20px",
79-
margin: "0",
80-
height: "100px",
81-
fontWeight: "normal",
82-
textAlign: "center",
83-
transition: "transform .3s"
84-
});
85-
86-
const Description = style("p")({
87-
padding: "20px",
88-
margin: "0",
89-
height: "100px",
90-
fontSize: "16px",
91-
opacity: "0.5"
92-
});
34+
const Cards = ({ children, loaded }) => {
35+
const scrollRef = useRef();
36+
const [showArrows, setShowArrows] = useState([false, false]);
9337

94-
const ClickZone = style("a")({
95-
margin: "0",
96-
":hover img": {
97-
transform: "scale(1.2)"
98-
},
99-
":hover hr": {
100-
opacity: "1"
101-
},
102-
":hover h3": {
103-
transform: "scale(1.2)"
104-
}
105-
});
38+
const getArrows = () => {
39+
const element = scrollRef.current.base;
40+
const scrollValue = element.scrollLeft;
41+
const maxScrollLeft = element.scrollWidth - element.clientWidth;
42+
return [scrollValue > 0, scrollValue < maxScrollLeft];
43+
};
10644

107-
export const Cards = ({ children }) => {
108-
const scrollRef = useRef();
109-
const [showArrows, setShowArrows] = useState([false, true]);
45+
useEffect(() => {
46+
if (loaded === true) {
47+
setShowArrows(getArrows());
48+
}
49+
}, [loaded]);
11050

11151
const scroll = direction => () => {
11252
const element = scrollRef.current.base;
11353
element.scrollBy({
11454
left: (direction * element.clientWidth * 80) / 100,
11555
behavior: "smooth"
11656
});
117-
setTimeout(() => {
118-
const scrollValue = element.scrollLeft;
119-
const maxScrollLeft = element.scrollWidth - element.clientWidth;
120-
setShowArrows([scrollValue > 0, scrollValue < maxScrollLeft]);
121-
}, 500);
57+
setTimeout(() => setShowArrows(getArrows()), 500);
12258
};
12359

12460
return html`
12561
<${CardsContainer}>
126-
<${Arrow} onClick=${scroll(-1)} show=${showArrows[0]}>
62+
<${Arrow} onClick=${scroll(-1)} show=${loaded && showArrows[0]}>
12763
${"<"}
12864
<//>
12965
<${CardsScroll} ref=${scrollRef}>
13066
${children}
13167
<//>
132-
<${Arrow} onClick=${scroll(1)} show=${showArrows[1]}>
68+
<${Arrow} onClick=${scroll(1)} show=${loaded && showArrows[1]}>
13369
${">"}
13470
<//>
13571
<//>
13672
`;
13773
};
13874

139-
export const Card = ({ title, image, link, description, exiting }) => html`
140-
<${CardContainer} exiting=${exiting}>
141-
<${ClickZone} href=${link} target="_blank" draggable=${false}>
142-
<${ImageContainer}>
143-
<${ImageBox}>
144-
<${Image} src=${image} alt=${title} draggable=${false} />
145-
<//>
146-
<//>
147-
<${Break} />
148-
<${Title} draggable=${false}>${title}<//>
149-
<${Description} draggable=${false}>${description}<//>
150-
<//>
151-
<//>
152-
`;
75+
export default Cards;

packages/client/src/components/content.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { useState, useEffect } from "preact/hooks";
22
import html from "../html";
33

4-
import { Cards, Card } from "./cards";
4+
import Cards from "./cards";
5+
import Card from "./card";
56

67
const Content = ({ type, exiting }) => {
78
const [items, setItems] = useState([]);
@@ -14,7 +15,7 @@ const Content = ({ type, exiting }) => {
1415
}, [type]);
1516

1617
return html`
17-
<${Cards}>
18+
<${Cards} loaded=${items.length > 0}>
1819
${items.map(
1920
item =>
2021
html`

packages/client/src/components/header.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ const HeaderComponent = ({ setContent }) => html`
7474
<${NavButton} onClick=${() => setContent("jobs")}>Jobs<//>
7575
<//>
7676
<${NavItem}>
77-
<${NavButton} onClick=${() => setContent("news")}>News<//>
77+
<${NavButton} onClick=${() => setContent("talks")}>Talks<//>
78+
<//>
79+
<${NavItem}>
80+
<${NavButton} onClick=${() => setContent("twitter")}>News<//>
7881
<//>
7982
<${NavItem}>
8083
<${NavButton} onClick=${() => setContent("about")}>About<//>

packages/client/src/components/main.js

+35-9
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,34 @@ const Main = style("main")({
1515
alignItems: "center"
1616
});
1717

18-
const Powered = style("a")({
19-
margin: "10px"
20-
});
18+
const Powered = style("a")(({ show }) => ({
19+
margin: "10px",
20+
opacity: show ? "1" : "0",
21+
transition: "opacity .5s"
22+
}));
23+
24+
const powereds = {
25+
medium: {
26+
link: "https://medium.com/@Swiip_51904",
27+
text: "Powered by Medium data (@Swiip_51904)"
28+
},
29+
github: {
30+
link: "https://github.com/Swiip",
31+
text: "Powered by GitHub data (@Swiip)"
32+
},
33+
jobs: {
34+
link: "https://www.contentful.com/",
35+
text: "Powered by Contentful"
36+
},
37+
talks: {
38+
link: "https://www.contentful.com/",
39+
text: "Powered by Contentful"
40+
},
41+
twitter: {
42+
link: "https://twitter.com/Swiip",
43+
text: "Powered by Twitter data (@Swiip)"
44+
}
45+
};
2146

2247
const MainComponent = ({ content }) => {
2348
const [type, setType] = useState("home");
@@ -42,12 +67,13 @@ const MainComponent = ({ content }) => {
4267
: html`
4368
<${Content} type=${type} exiting=${exiting} />
4469
`}
45-
${type === "medium" &&
46-
html`
47-
<${Powered} href="https://medium.com/@Swiip_51904" target="_blank">
48-
Powered by Medium (@Swiip_51904)
49-
<//>
50-
`}
70+
<${Powered}
71+
show=${powereds[type] && !exiting}
72+
href=${powereds[type] && powereds[type].link}
73+
target="_blank"
74+
>
75+
${powereds[type] && powereds[type].text}
76+
<//>
5177
<//>
5278
`;
5379
};

packages/server/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"express": "^4.16.4",
99
"graphql-request": "^1.8.2",
1010
"node-fetch": "^2.5.0",
11+
"twit": "^2.2.11",
1112
"xml2js": "^0.4.19"
1213
}
1314
}

packages/server/talks.js

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { stringify } from "querystring";
2+
import fetch from "node-fetch";
3+
import express from "express";
4+
5+
const app = express();
6+
7+
const spaceId = "yiag7v31k8be";
8+
const url = `https://cdn.contentful.com/spaces/${spaceId}/entries`;
9+
const token = process.env.CONTENTFUL_API_TOKEN;
10+
11+
app.get("*", async (req, res) => {
12+
const queryString = stringify({
13+
access_token: token,
14+
content_type: "talk"
15+
});
16+
const request = await fetch(`${url}?${queryString}`);
17+
const data = await request.json();
18+
19+
const getImage = imageId =>
20+
data.includes.Asset.find(asset => asset.sys.id === imageId);
21+
22+
const mapped = data.items.map(item => {
23+
const date = new Date(item.fields.date);
24+
return {
25+
title: `${item.fields.conference}, ${item.fields.talk}`,
26+
image: getImage(item.fields.image.sys.id).fields.file.url,
27+
date,
28+
link: item.fields.link,
29+
description: `${date.toDateString()}, ${item.fields.location}`
30+
};
31+
});
32+
33+
const sorted = mapped.sort((a, b) => b.date.getTime() - a.date.getTime());
34+
35+
res.send(sorted);
36+
});
37+
38+
export default app;

0 commit comments

Comments
 (0)