Skip to content

Commit 2fbcc01

Browse files
committed
Res sub-components added, sequence params, responsive
1 parent 5991721 commit 2fbcc01

File tree

13 files changed

+253
-33
lines changed

13 files changed

+253
-33
lines changed

lib/components/Res.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import React from "react";
2+
import PropTypes from "prop-types";
3+
4+
const Render = ({ component }) => {
5+
return <param type="render" content={component} />;
6+
};
7+
8+
Render.propTypes = {
9+
component: PropTypes.func,
10+
};
11+
12+
const Content = ({ json, contentType, text }) => {
13+
const ComponentsArray = [];
14+
15+
if (contentType)
16+
ComponentsArray.push(
17+
<param key="contentType" type="content-type" content={contentType} />
18+
);
19+
if (json)
20+
ComponentsArray.push(<param key="json" type="json" content={json} />);
21+
if (text)
22+
ComponentsArray.push(<param key="text" type="text" content={text} />);
23+
24+
return ComponentsArray;
25+
};
26+
27+
Content.propTypes = {
28+
json: PropTypes.any,
29+
contentType: PropTypes.string,
30+
text: PropTypes.string,
31+
};
32+
33+
const Status = ({ statusCode }) => {
34+
return <param type="status" content={statusCode} />;
35+
};
36+
37+
Status.propTypes = {
38+
statusCode: PropTypes.number,
39+
};
40+
41+
const Redirect = ({ path, statusCode }) => {
42+
return <param type="redirect" content={{ path, statusCode }} />;
43+
};
44+
45+
Redirect.propTypes = {
46+
path: PropTypes.string.isRequired,
47+
statusCode: PropTypes.number,
48+
};
49+
50+
const SendFile = ({ path, options, onError = () => {} }) => {
51+
return <param type="send-file" content={{ path, options, onError }} />;
52+
};
53+
54+
SendFile.propTypes = {
55+
path: PropTypes.string.isRequired,
56+
options: PropTypes.object,
57+
onError: PropTypes.func,
58+
};
59+
60+
export const Res = {
61+
Render,
62+
Content,
63+
Status,
64+
Redirect,
65+
SendFile,
66+
};

lib/components/Routes.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,33 @@
11
import React from "react";
22
import PropTypes from "prop-types";
3-
import { METHODS } from "../renderer/helpers";
3+
import { Res } from "./Res";
44

55
const BaseRoute = (method) => {
6-
const RouteComponent = ({ path, content, children }) => (
7-
<route method={method} path={path} content={content}>
6+
const RouteComponent = ({
7+
children,
8+
path,
9+
handler,
10+
render,
11+
status,
12+
json,
13+
text,
14+
}) => (
15+
<route method={method} path={path} handler={handler}>
816
{children}
17+
{render && <Res.Render component={render} />}
18+
{status && <Res.Status statusCode={status} />}
19+
{text && <Res.Content text={text} />}
20+
{json && <Res.Content json={json} />}
921
</route>
1022
);
1123

1224
RouteComponent.propTypes = {
1325
path: PropTypes.string,
14-
content: PropTypes.any,
1526
handler: PropTypes.func,
27+
render: PropTypes.func,
28+
status: PropTypes.number,
29+
json: PropTypes.any,
30+
text: PropTypes.string,
1631
};
1732

1833
return RouteComponent;

lib/components/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export * from "./App";
22
export * from "./Static";
33
export * from "./Router";
44
export * from "./Routes";
5+
export * from "./Res";

lib/renderer/generateRoute.js

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import React from "react";
1+
import React, { Children } from "react";
22
import { renderToString } from "react-dom/server";
33
import { ServerStyleSheet } from "styled-components";
44
import { Helmet } from "react-helmet";
55
import { ReqResContext } from "../context";
6+
import { Res } from "../components";
67

78
const sheet = new ServerStyleSheet();
89

@@ -21,6 +22,8 @@ function renderPage(Component, req, res) {
2122
<!DOCTYPE html>
2223
<html ${helmet.htmlAttributes.toString()}>
2324
<head>
25+
<meta charset="UTF-8">
26+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
2427
${helmet.title.toString()}
2528
${helmet.meta.toString()}
2629
${helmet.link.toString()}
@@ -37,20 +40,53 @@ function renderPage(Component, req, res) {
3740
res.send(html);
3841
}
3942

43+
function paramfn(sq, req, res, next) {
44+
for (const param of sq) {
45+
switch (param.type) {
46+
case "json":
47+
res.send(param.content);
48+
break;
49+
case "text":
50+
res.send(param.content);
51+
break;
52+
case "status":
53+
res.statusCode = param.content;
54+
break;
55+
case "contentType":
56+
res.setHeader("Content-Type", param.content);
57+
break;
58+
case "redirect":
59+
if (param.content.statusCode)
60+
res.redirect(param.content.statusCode, param.content.path);
61+
else res.redirect(param.content.path);
62+
res.end();
63+
break;
64+
case "render":
65+
renderPage(param.content, req, res);
66+
break;
67+
case "send-file":
68+
res.sendFile(param.content.path, param.content.options, (err) => {
69+
if (err) {
70+
param.content.onError(err);
71+
next();
72+
}
73+
});
74+
break;
75+
default:
76+
}
77+
}
78+
}
79+
4080
export function generateRoute(parentInstance, props) {
4181
parentInstance.routerInstance[props.method](
4282
props.path || "/",
4383
...[
4484
...(props.middlewares || []),
4585
async (req, res, next) => {
46-
if (props.content) {
47-
if (props.status) res.status(props.status);
48-
if (typeof props.content === "function") {
49-
renderPage(props.content, req, res);
50-
} else {
51-
res.send(props.content);
52-
}
86+
if (props.paramsSeq) {
87+
paramfn(props.paramsSeq, req, res, next);
5388
}
89+
5490
if (props.handler)
5591
await props.handler(req, res, next, (Component) =>
5692
renderPage(Component, req, res)

lib/renderer/index.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ let reconciler = ReactReconciler({
4343
}
4444

4545
if (type === "route") {
46+
let paramsSeq = [];
47+
return {
48+
type,
49+
props: { ...props, paramsSeq },
50+
};
51+
}
52+
53+
if (type === "param") {
4654
return {
4755
type,
4856
props,
@@ -78,6 +86,10 @@ let reconciler = ReactReconciler({
7886
return;
7987
}
8088

89+
if (child.type === "param") {
90+
parentInstance.props.paramsSeq.push(child.props);
91+
}
92+
8193
if (child.static) {
8294
parentInstance.use(
8395
...(child.path ? [child.path, child.static] : [child.static])

public/code-example.png

-69.2 KB
Loading

public/logo.svg

100644100755
File mode changed.

src/app.js

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,47 @@
11
import React from "react";
2+
import { ReactXpress, App, Static, Router, Get, Post, Res } from "../lib";
23
import { HomePage } from "./pages/HomePage";
34
import { ComponentsPage } from "./pages/ComponentsPage";
4-
import { ReactXpress, App, Static, Router, Get, Post } from "../lib";
5+
import { resolve } from "path";
56

67
const ExpressApp = () => (
78
<App port={process.env.PORT || 8080}>
89
<Static publicPath="/public" />
910
<Router path="/">
10-
<Get content={HomePage} />
11-
<Router path="/components">
12-
<Get content={ComponentsPage} />
13-
</Router>
11+
<Get render={HomePage} />
12+
<Get path="/components" render={ComponentsPage} />
1413
<Router path="/api">
15-
<Post path="/status" content={{ msg: "It is okay, bro" }} />
14+
<Post
15+
path="/status"
16+
json={{ msg: "It is okay, bro" }}
17+
handler={(req, res) => console.log(req.originalUrl)}
18+
/>
1619
</Router>
17-
<Get path="*" content="Not Found" status={404} />
20+
<Updates />
21+
<Get path="*" text="Not Found" status={404} />
1822
</Router>
1923
</App>
2024
);
2125

26+
const Updates = () => (
27+
<>
28+
<Get path="/redirect">
29+
<Res.Redirect statusCode={301} path="https://ru.reactjs.org" />
30+
</Get>
31+
<Post path="/json">
32+
<Res.Status statusCode={401} />
33+
<Res.Content json={{ msg: "No Access" }} contentType="application/json" />
34+
</Post>
35+
<Get path="/send-file">
36+
<Res.SendFile
37+
path={resolve("public/code-example.png")}
38+
onError={console.log}
39+
/>
40+
</Get>
41+
<Get path="/render">
42+
<Res.Render component={() => <h1>Shut Up And Take My Money!</h1>} />
43+
</Get>
44+
</>
45+
);
46+
2247
ReactXpress.render(<ExpressApp />);

src/components/layout/GlobalStyle.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ export const GlobalStyle = createGlobalStyle`
1010
box-sizing: inherit;
1111
}
1212
13+
body {
14+
background-color: #131516;
15+
}
16+
1317
body, h1, h2, h3, h4, h5, h6, p, ol, ul {
1418
margin: 0;
1519
padding: 0;

src/components/layout/TopNav.js

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,32 @@
1-
import React, { useContext } from "react";
1+
import React, { useContext, useMemo } from "react";
22
import styled from "styled-components";
33
import { ReqResContext } from "../../../lib";
44

5+
const PAGES = [
6+
{ path: "/", label: "Home", title: "@orkhanjafarovr" },
7+
{ path: "/components", label: "Components", title: "Components Page" },
8+
{
9+
path: "https://github.com/gigantz/react-xpress",
10+
label: "Github",
11+
title: "Github",
12+
},
13+
];
14+
515
export const TopNav = () => {
616
const { req } = useContext(ReqResContext);
17+
const pageTitle = useMemo(
18+
() => PAGES.find((p) => p.path === req.originalUrl).title,
19+
[req]
20+
);
21+
722
return (
823
<TopWrapper currentPath={req.originalUrl}>
9-
<Logo href="/"> </Logo>
10-
<NavItem href="/">Home</NavItem>
11-
<NavItem href="/components">Components</NavItem>
12-
<NavItem href="https://github.com/gigantz/react-xpress">Github</NavItem>
24+
<Logo href="/">{pageTitle}</Logo>
25+
{PAGES.map((page) => (
26+
<NavItem key={page.path} href={page.path}>
27+
{page.label}
28+
</NavItem>
29+
))}
1330
</TopWrapper>
1431
);
1532
};
@@ -39,6 +56,10 @@ const TopWrapper = styled.nav`
3956
background-color: ${(props) => props.theme.colors.brandVeryLight};
4057
}
4158
}
59+
60+
@media (max-width: 600px) {
61+
justify-content: center;
62+
}
4263
`;
4364

4465
const Logo = styled.a`
@@ -51,10 +72,9 @@ const Logo = styled.a`
5172
text-decoration: none;
5273
margin-right: auto;
5374
padding: 0 10px;
54-
opacity: 0.1;
5575
56-
&:hover {
57-
opacity: 1;
76+
@media (max-width: 600px) {
77+
display: none;
5878
}
5979
`;
6080

0 commit comments

Comments
 (0)