diff --git a/package-lock.json b/package-lock.json index 424411e..7edf68d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3993,8 +3993,7 @@ "deep-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", - "dev": true + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" }, "deep-extend": { "version": "0.6.0", @@ -4774,6 +4773,11 @@ "meow": "^3.1.0" } }, + "exenv": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz", + "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50=" + }, "exif-parser": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", @@ -13166,6 +13170,17 @@ "prop-types": "^15.6.0" } }, + "react-helmet": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-5.2.0.tgz", + "integrity": "sha1-qBgR3yExOm1VxfBYxK66XW89l6c=", + "requires": { + "deep-equal": "^1.0.1", + "object-assign": "^4.1.1", + "prop-types": "^15.5.4", + "react-side-effect": "^1.1.0" + } + }, "react-hot-loader": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.3.3.tgz", @@ -13227,6 +13242,15 @@ "warning": "^4.0.1" } }, + "react-side-effect": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-1.1.5.tgz", + "integrity": "sha512-Z2ZJE4p/jIfvUpiUMRydEVpQRf2f8GMHczT6qLcARmX7QRb28JDBTpnM2g/i5y/p7ZDEXYGHWg0RbhikE+hJRw==", + "requires": { + "exenv": "^1.2.1", + "shallowequal": "^1.0.1" + } + }, "read-all-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", @@ -14385,8 +14409,7 @@ "shallowequal": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.0.2.tgz", - "integrity": "sha512-zlVXeVUKvo+HEv1e2KQF/csyeMKx2oHvatQ9l6XjCUj3agvC8XGf6R9HvIPDSmp8FNPvx7b5kaEJTRi7CqxtEw==", - "dev": true + "integrity": "sha512-zlVXeVUKvo+HEv1e2KQF/csyeMKx2oHvatQ9l6XjCUj3agvC8XGf6R9HvIPDSmp8FNPvx7b5kaEJTRi7CqxtEw==" }, "shebang-command": { "version": "1.2.0", diff --git a/package.json b/package.json index beaa289..5f14f87 100644 --- a/package.json +++ b/package.json @@ -89,6 +89,7 @@ "mobx": "^5.0.3", "mobx-react": "^5.2.3", "normalize.css": "^8.0.0", + "react-helmet": "^5.2.0", "react-router": "^4.3.1", "react-router-dom": "^4.3.1" }, diff --git a/plop-templates/component.tsx b/plop-templates/component.tsx index 9cda7ef..92d5dcc 100644 --- a/plop-templates/component.tsx +++ b/plop-templates/component.tsx @@ -6,8 +6,9 @@ import {{ camelCase store_name }} from "../../stores/{{ properCase store_name }} import "./{{ properCase name}}.scss"; export interface {{ properCase name }}Props {} +export interface {{ properCase name }}State {} -{{#if observer}}@observer{{/if}} class {{ properCase name }} extends React.Component<{{ properCase name }}Props, undefined> { +{{#if observer}}@observer{{/if}} class {{ properCase name }} extends React.Component<{{ properCase name }}Props, {{ properCase name }}State> { render() { return (
diff --git a/plop-templates/page.scss b/plop-templates/page.scss new file mode 100644 index 0000000..2bedf49 --- /dev/null +++ b/plop-templates/page.scss @@ -0,0 +1,3 @@ +.{{ dashCase name }} { + +} diff --git a/plop-templates/page.tsx b/plop-templates/page.tsx new file mode 100644 index 0000000..5411e82 --- /dev/null +++ b/plop-templates/page.tsx @@ -0,0 +1,21 @@ +import * as React from "react"; +import Helmet from "react-helmet"; +import "./{{ properCase name}}.scss"; + +export interface {{ properCase name }}Props {} +export interface {{ properCase name }}State {} + +class {{ properCase name }} extends React.Component<{{ properCase name }}Props, {{ properCase name }}State> { + render() { + return ( +
+ + + + {{ titleCase name }} +
+ ); + } +} + +export default {{ properCase name }}; diff --git a/plopfile.ts b/plopfile.ts index c77941d..1d9538f 100644 --- a/plopfile.ts +++ b/plopfile.ts @@ -41,6 +41,36 @@ module.exports = function(plop) { } ] }); + plop.setGenerator("New page", { + description: "Create a new TSX + SCSS page for React.", + prompts: [ + { + type: "input", + name: "name", + message: "Page name (has to end in \"page\"):" + }, + ], + actions: [ + { + type: "add", + path: "src/pages/{{ properCase name }}/{{ properCase name }}.tsx", + templateFile: "plop-templates/page.tsx", + abortOnFail: true + }, + { + type: "add", + path: "src/pages/{{ properCase name }}/{{ properCase name }}.scss", + templateFile: "plop-templates/page.scss", + abortOnFail: true + }, + { + type: "add", + path: "src/pages/{{ properCase name }}/index.ts", + templateFile: "plop-templates/index.ts", + abortOnFail: true + } + ] + }); plop.setGenerator("New MobX state store", { description: "Create a new store for MobX.", prompts: [ diff --git a/src/components/App/index.ts b/src/components/App/index.ts deleted file mode 100644 index 144ee68..0000000 --- a/src/components/App/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import App from "./App"; -export default App; \ No newline at end of file diff --git a/src/components/App/App.scss b/src/pages/FrontPage/FrontPage.scss similarity index 100% rename from src/components/App/App.scss rename to src/pages/FrontPage/FrontPage.scss diff --git a/src/components/App/App.tsx b/src/pages/FrontPage/FrontPage.tsx similarity index 78% rename from src/components/App/App.tsx rename to src/pages/FrontPage/FrontPage.tsx index 3f52404..73e6f0c 100644 --- a/src/components/App/App.tsx +++ b/src/pages/FrontPage/FrontPage.tsx @@ -1,11 +1,12 @@ import * as React from "react"; import { observer } from "mobx-react"; -import "./App.scss"; +import Helmet from "react-helmet"; +import "./FrontPage.scss"; import appStore from "../../stores/AppStore"; -import Button from "../Button"; import { getPosts, Post as PostInterface } from "../../models/Post"; -import Post from "../Post"; -import JsonLD from "../JsonLD"; +import Button from "../../components/Button"; +import Post from "../../components/Post"; +import JsonLD from "../../components/JsonLD"; export interface AppProps { appStore: { @@ -19,7 +20,7 @@ export interface AppState { error: string | Error; } -@observer class App extends React.Component { +@observer class FrontPage extends React.Component { constructor(props) { super(props); this.fetchPosts = this.fetchPosts.bind(this); @@ -45,6 +46,9 @@ export interface AppState { render() { return
+ + +

Aalto-yliopiston sähköinsinöörikilta!

Sähköä, viinaa, naisia.

@@ -67,4 +71,4 @@ export interface AppState { } } -export default props => ; +export default props => ; diff --git a/src/pages/FrontPage/index.ts b/src/pages/FrontPage/index.ts new file mode 100644 index 0000000..ca980cd --- /dev/null +++ b/src/pages/FrontPage/index.ts @@ -0,0 +1,2 @@ +import FrontPage from "./FrontPage"; +export default FrontPage; \ No newline at end of file diff --git a/src/components/NotFoundPage/NotFoundPage.scss b/src/pages/NotFoundPage/NotFoundPage.scss similarity index 100% rename from src/components/NotFoundPage/NotFoundPage.scss rename to src/pages/NotFoundPage/NotFoundPage.scss diff --git a/src/components/NotFoundPage/NotFoundPage.tsx b/src/pages/NotFoundPage/NotFoundPage.tsx similarity index 59% rename from src/components/NotFoundPage/NotFoundPage.tsx rename to src/pages/NotFoundPage/NotFoundPage.tsx index a559d2c..faa725f 100644 --- a/src/components/NotFoundPage/NotFoundPage.tsx +++ b/src/pages/NotFoundPage/NotFoundPage.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import Helmet from "react-helmet"; import "./NotFoundPage.scss"; export interface NotFoundPageProps {} @@ -7,6 +8,11 @@ export interface NotFoundPageProps {} render() { return (
+ + + 404 | Ei vaan löydy + + 404 | Ei vaan löydy
); diff --git a/src/components/NotFoundPage/index.ts b/src/pages/NotFoundPage/index.ts similarity index 100% rename from src/components/NotFoundPage/index.ts rename to src/pages/NotFoundPage/index.ts diff --git a/src/routes.tsx b/src/routes.tsx index 7b3e2fa..6d97f45 100644 --- a/src/routes.tsx +++ b/src/routes.tsx @@ -1,11 +1,11 @@ import * as React from "react"; import { Switch, Route } from "react-router-dom"; -import App from "./components/App"; -import NotFoundPage from "./components/NotFoundPage"; +import FrontPage from "./pages/FrontPage"; +import NotFoundPage from "./pages/NotFoundPage"; const Routes = () => ( - + ); diff --git a/tests/testcafe/404.test.ts b/tests/testcafe/404.test.ts new file mode 100644 index 0000000..93e52c7 --- /dev/null +++ b/tests/testcafe/404.test.ts @@ -0,0 +1,17 @@ +/** + * TestCafé test fixtures. + * This file is used by TestCafé to run end-to-end tests with chrome against the site. + * Tests are grouped into fixtures and fixtures into files. + */ +import { Selector } from "testcafe"; + +fixture`404 page renders and functions correctly`.page("http://localhost:3000/404"); + +test("Page contains the text 404", async t => { + /** + * Test if there is a favicon element on the page + */ + const elem = Selector(".not-found-page"); + await t.expect(elem.textContent).contains("404"); +}); +