This commit is contained in:
Arwed Mett 2018-02-16 20:52:28 +01:00
parent fdac043d4b
commit d8d75ab752
10 changed files with 143 additions and 48 deletions

View File

@ -1,22 +1,27 @@
//@flow //@flow
import React from "react" import React from "react"
import { Header, Projects, Contact } from "./components" import { Header, Projects, Contact } from "./components"
import { Body, Section, Content } from "./elements" import { Body, Section, content } from "./elements"
import NoscriptWarning from "./noscript" import NoscriptWarning from "./noscript"
import { ThemeProvider } from "styled-components" import { ThemeProvider } from "styled-components"
import { Dark } from "./themes" import { Dark } from "./themes"
const projects = {
title: "My Projects",
body: () => <Projects />
}
const contact = {
title: "Contact",
body: () => <Contact />
}
export default () => <ThemeProvider theme={ Dark }> export default () => <ThemeProvider theme={ Dark }>
<Body> <Body>
<NoscriptWarning /> <NoscriptWarning />
<Header /> <Header />
<Content> { content([
<Section title="My Projects"> projects,
<Projects /> contact
</Section> ]) }
<Section title="Contact">
<Contact />
</Section>
</Content>
</Body> </Body>
</ThemeProvider> </ThemeProvider>

View File

@ -1,39 +1,90 @@
//@flow //@flow
import React, { Component, Node } from "react" import React, { Component } from "react"
import type { Node } from "react"
import { Section } from "."
import type { SectionDescription } from "."
import styled from "styled-components"
import Observer from "@researchgate/react-intersection-observer"
type LinkProps = { const Link = styled.a`
title: String, text-decoration: inherit;
target: Node color: white;
} min-height: 40px;
display: flex;
align-items: center;
padding: 0 20px;
type LinkState = { transition: 0.3s ease;
target: Node :hover {
} background-color: #777;
class Link extends Component<LinkProps, LinkState> {
constructor(props) {
super(props)
const { target } = props
this.setState({ target })
} }
} `
type ContentProps = { const Header = styled.header.attrs({
children: React.Node backgroundcolor: props => props.theme.backgroundcolor || "#111111"
} })`
position: sticky;
top: 0;
display: flex;
justify-content: left;
align-items: center;
width: 60%;
z-index: 5;
margin: 20px auto;
min-height: 40px;
border-bottom: solid white;
background-color: ${ props => props.backgroundcolor };
`
type ContentState = { /**
* create a hash based on the section title
*/
const get_hash = (section: SectionDescription, key: number) =>
key + "-" + section.title.toLocaleLowerCase().split(" ").join("-")
} /**
* create a link to the section, according to the name and key.
*/
const create_link = (section: SectionDescription, key: number) =>
<Link href={ "#" + get_hash(section, key) } key={ key }>{ section.title }</Link>
class Content extends Component<ContentProps, ContentState> { /**
render() { * create a link for every section.
const { children } = this.props */
return <div> const generate_links = (sections: Array<SectionDescription>) => sections.map(create_link)
{ children }
</div>
}
}
export default Content /**
* transform a section description intto a section.
*/
const create_section = (description: SectionDescription, key: number) =>
<Section
description={ description }
hash={ get_hash(description, key) }
key={ key }
/>
/**
* create a list of sections from their description.
*/
const generate_sections = (descriptions: Array<SectionDescription>) =>
descriptions.map(create_section)
const Sentinel = styled.div`
width: 100%;
height: 1px;
`
const test = () => alert("test")
export default (sections: Array<SectionDescription>) => <div>
<Observer onChange={ test } root="body" rootMargin="0% 0% 0% 0%">
<Sentinel />
</Observer>
<Header onWheel={ test }>
{ generate_links(sections) }
</Header>
{ generate_sections(sections) }
</div>

View File

@ -6,13 +6,10 @@ export {
Name as HeaderName Name as HeaderName
} from "./header" } from "./header"
export { export { Body } from "./body"
Body
} from "./body"
export { export { default as Section } from "./section"
default as Section export type { SectionDescription } from "./section"
} from "./section"
export { export {
default as Project, default as Project,
@ -23,4 +20,5 @@ export {
H1, H2, Title, P H1, H2, Title, P
} from "./text" } from "./text"
export { default as Content } from "./content" export { default as content } from "./content"

View File

@ -18,8 +18,13 @@ const Style = styled.section`
const Title = H1 const Title = H1
export default (props: { title: string, children?: Node }) => <Style> export type SectionDescription = {
<Title>{ props.title }</Title> title: string,
body: () => Node
}
export default (props: { description: SectionDescription, hash: string }) => <Style>
<Title id={ props.hash || "" }>{ props.description.title }</Title>
<br /> <br />
<div>{ props.children }</div> <div>{ props.description.body() }</div>
</Style> </Style>

3
src/util/index.js Normal file
View File

@ -0,0 +1,3 @@
//@flow
export { default as map } from "./map"

4
src/util/map.js Normal file
View File

@ -0,0 +1,4 @@
//@flow
export default <A, B>(f: (A, number) => B) => (elements: Array<A>) => elements.map(f)

View File

@ -0,0 +1,7 @@
//@flow
import util from "./util"
describe("homepage", () => {
util()
})

9
test/util/index.js Normal file
View File

@ -0,0 +1,9 @@
//@flow
import map from "./map"
export default () => {
describe("util", () => {
map()
})
}

13
test/util/map.js Normal file
View File

@ -0,0 +1,13 @@
//@flow
import { map } from "../../src/util"
import assert from "assert"
export default () => {
describe("map", () => {
const numbers = [1, 2, 3, 4, 5, 6, 7]
const numbers_plus_1 = map(x => x + 1)(numbers)
it("add one to all members", () => {
assert.deepEqual(numbers_plus_1, [2, 3, 4, 5, 6, 7, 8])
})
})
}

View File

@ -102,7 +102,7 @@ const development = config => Object.assign({ }, config(), {
stats: 'errors-only', stats: 'errors-only',
host: process.env.HOST, host: process.env.HOST,
port: 3000, port: 5000,
compress: true, compress: true,
overlay: true, overlay: true,
hot: true, hot: true,