initial app
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import { Global } from "@emotion/react";
|
||||
import normalizeCss from "normalize.css/normalize.css?inline";
|
||||
import React from "react";
|
||||
import { IntlProvider } from "react-intl";
|
||||
|
||||
import Router from "./views/Router";
|
||||
|
||||
const App: React.FC = () => {
|
||||
return (
|
||||
<IntlProvider locale="en" defaultLocale="en">
|
||||
<Global styles={normalizeCss} />
|
||||
<Router />
|
||||
</IntlProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
|
||||
type ErrorHandler = (error: Error, info: React.ErrorInfo) => void;
|
||||
type ErrorHandlingComponent<Props> = (
|
||||
props: Props,
|
||||
error?: Error
|
||||
) => React.ReactNode;
|
||||
|
||||
type ErrorState = { error?: Error };
|
||||
|
||||
function Catch<Props extends object>(
|
||||
component: ErrorHandlingComponent<Props>,
|
||||
errorHandler?: ErrorHandler
|
||||
): React.ComponentType<Props> {
|
||||
function Inner({ error, props }: { error?: Error; props: Props }) {
|
||||
return <React.Fragment>{component(props, error)}</React.Fragment>;
|
||||
}
|
||||
|
||||
return class CatchClass extends React.Component<Props, ErrorState> {
|
||||
state: ErrorState = {
|
||||
error: undefined,
|
||||
};
|
||||
|
||||
static getDerivedStateFromError(error: Error) {
|
||||
return { error };
|
||||
}
|
||||
|
||||
componentDidCatch(error: Error, info: React.ErrorInfo) {
|
||||
if (errorHandler) {
|
||||
errorHandler(error, info);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <Inner error={this.state.error} props={this.props} />;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const divStyles: React.CSSProperties = {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
};
|
||||
|
||||
const ErrorBoundary = Catch(function (
|
||||
props: React.PropsWithChildren,
|
||||
error?: Error
|
||||
) {
|
||||
if (error) {
|
||||
return (
|
||||
<div style={divStyles}>
|
||||
<h2>
|
||||
There was an error on the page. Please reload the application and try
|
||||
again.
|
||||
</h2>
|
||||
<p />
|
||||
<p>{error.message}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return <>{props.children}</>;
|
||||
});
|
||||
|
||||
export default ErrorBoundary;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as ErrorBoundary } from "./ErrorBoundary";
|
||||
@@ -0,0 +1,56 @@
|
||||
import styled from "@emotion/styled";
|
||||
import React from "react";
|
||||
|
||||
import MainNavigation from "../Navigation/MainNavigation";
|
||||
|
||||
const Root = styled("div")({
|
||||
background: "rgb(215, 215, 215)",
|
||||
});
|
||||
|
||||
const Container = styled("div")({
|
||||
alignItems: "stretch",
|
||||
display: "flex",
|
||||
margin: "0 auto",
|
||||
maxWidth: 1600,
|
||||
minHeight: "100vh",
|
||||
width: "100vw",
|
||||
});
|
||||
|
||||
const Nav = styled("nav")({
|
||||
background: "rgb(41, 62, 73)",
|
||||
color: "white",
|
||||
flex: "0 0 280px",
|
||||
padding: "8px 20px",
|
||||
|
||||
"@media (max-width: 600px)": {
|
||||
display: "none",
|
||||
},
|
||||
|
||||
"& a": {
|
||||
color: "white",
|
||||
},
|
||||
});
|
||||
|
||||
const Main = styled("main")({
|
||||
background: "rgb(245, 245, 245)",
|
||||
color: "rgb(25, 25, 25)",
|
||||
flex: "1 0 500px",
|
||||
padding: "8px 20px",
|
||||
});
|
||||
|
||||
const MainLayout: React.FC<React.PropsWithChildren> = (props) => {
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<Container>
|
||||
<Nav>
|
||||
<MainNavigation />
|
||||
</Nav>
|
||||
<Main>{children}</Main>
|
||||
</Container>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainLayout;
|
||||
@@ -0,0 +1,8 @@
|
||||
import styled from "@emotion/styled";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
const Link = styled(RouterLink)({
|
||||
color: "rgb(35, 115, 220)",
|
||||
});
|
||||
|
||||
export default Link;
|
||||
@@ -0,0 +1 @@
|
||||
export { default as Link } from "./Link";
|
||||
@@ -0,0 +1,12 @@
|
||||
import React from "react";
|
||||
|
||||
const MainNavigation: React.FC = () => {
|
||||
return (
|
||||
<>
|
||||
<p>Contact</p>
|
||||
<a href="mailto:linkedin@c3c.cz">linkedin@c3c.cz</a>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainNavigation;
|
||||
@@ -0,0 +1,13 @@
|
||||
interface ConfigFromBackend {
|
||||
commitTime: string;
|
||||
}
|
||||
|
||||
interface MyWindow extends Window {
|
||||
APP_CONFIG?: ConfigFromBackend;
|
||||
}
|
||||
|
||||
declare const window: MyWindow;
|
||||
|
||||
export const BUILD_TIMESTAMP: Date = window.APP_CONFIG?.commitTime
|
||||
? new Date(window.APP_CONFIG.commitTime)
|
||||
: new Date();
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
|
||||
import App from "./App";
|
||||
|
||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
@@ -0,0 +1,15 @@
|
||||
import React from "react";
|
||||
|
||||
import MainLayout from "../components/Layout/MainLayout";
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
return (
|
||||
<MainLayout>
|
||||
<h1>Lukáš Čech</h1>
|
||||
<h2>DevOps Engineer</h2>
|
||||
<p>(For the lack of a better name)</p>
|
||||
</MainLayout>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
@@ -0,0 +1,34 @@
|
||||
import styled from "@emotion/styled";
|
||||
import React from "react";
|
||||
import { defineMessages, useIntl } from "react-intl";
|
||||
|
||||
import { Link } from "../components/Link";
|
||||
|
||||
const messages = defineMessages({
|
||||
notFound: {
|
||||
defaultMessage: "Nothing to see here",
|
||||
id: "Router.NotFound",
|
||||
},
|
||||
});
|
||||
|
||||
const Root = styled("div")({
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
height: "100vh",
|
||||
width: "100vw",
|
||||
});
|
||||
|
||||
const NotFound = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<p>{intl.formatMessage(messages.notFound)}</p>
|
||||
<Link to="/">Go home</Link>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotFound;
|
||||
@@ -0,0 +1,39 @@
|
||||
import React from "react";
|
||||
import { Outlet, RouterProvider } from "react-router-dom";
|
||||
import { createBrowserRouter } from "react-router-dom";
|
||||
|
||||
import { ErrorBoundary } from "../components/ErrorBoundary";
|
||||
import Dashboard from "./Dashboard";
|
||||
|
||||
const Layout: React.FC = () => {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Outlet />
|
||||
</ErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
||||
const NotFound = React.lazy(() => import("./NotFound"));
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
element: <Layout />,
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
element: <Dashboard />,
|
||||
},
|
||||
{
|
||||
path: "*",
|
||||
element: <NotFound />,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
const Router = (): JSX.Element => {
|
||||
return <RouterProvider router={router} />;
|
||||
};
|
||||
|
||||
export default Router;
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="vite/client" />
|
||||
Reference in New Issue
Block a user