diff --git a/BuildConfig.sh b/BuildConfig.sh index fc9dfae..db154c1 100644 --- a/BuildConfig.sh +++ b/BuildConfig.sh @@ -1,36 +1,31 @@ -#!/bin/bash -rm -f /app/src/config.js; -if [ -z "$BACKEND_HOST" ]; then - BACKEND_HOST="http://localhost:5000" -fi -if [ -z "$FRONTEND_HOST" ]; then - FRONTEND_HOST="http://localhost:3000" -fi -if [ -z "$KC_CLIENT_ID" ]; then - KC_CLIENT_ID="labdev" -fi -if [ -z "$KC_HOST" ]; then - KC_HOST="https://login.hangman-lab.top" -fi -if [ -z "$KC_REALM" ]; then - KC_REALM="Hangman-Lab" -fi +#!/bin/sh -mkdir -p /app/src +BACKEND_HOST="${BACKEND_HOST:-http://localhost:5000}" +FRONTEND_HOST="${FRONTEND_HOST:-http://localhost:80}" +KC_CLIENT_ID="${KC_CLIENT_ID:-labdev}" +KC_HOST="${KC_HOST:-https://login.hangman-lab.top}" +KC_REALM="${KC_REALM:-Hangman-Lab}" -echo " -const config = { - BACKEND_HOST: \"${BACKEND_HOST}\", - FRONTEND_HOST: \"${FRONTEND_HOST}\", - KC_CLIENT_ID: \"${KC_CLIENT_ID}\", - OIDC_CONFIG: { - authority: \"${KC_HOST}/realms/${KC_REALM}\", - client_id: \"${KC_CLIENT_ID}\", - redirect_uri: \"${FRONTEND_HOST}/callback\", - post_logout_redirect_uri: \"${FRONTEND_HOST}\", - response_type: \"code\", - scope: \"openid profile email roles\", - }, -}; -export default config; -" > /app/src/config.js; +rm -f /usr/share/nginx/html/config.js + + + +cat < /usr/share/nginx/html/config.json +{ + "BACKEND_HOST": "${BACKEND_HOST}", + "FRONTEND_HOST": "${FRONTEND_HOST}", + "KC_CLIENT_ID": "${KC_CLIENT_ID}", + "OIDC_CONFIG": { + "authority": "${KC_HOST}/realms/${KC_REALM}", + "client_id": "${KC_CLIENT_ID}", + "redirect_uri": "${FRONTEND_HOST}/callback", + "post_logout_redirect_uri": "${FRONTEND_HOST}", + "response_type": "code", + "scope": "openid profile email roles", + "popup_redirect_uri": "${FRONTEND_HOST}/popup_callback", + "silent_redirect_uri": "${FRONTEND_HOST}/silent_callback" + } +} +EOL + +exec "$@" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 99e6846..958c2a6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,27 @@ -FROM node:18 as build-stage +FROM node:18-alpine AS build-stage WORKDIR /app + COPY package*.json ./ RUN npm install COPY . . -COPY BuildConfig.sh /app/BuildConfig.sh -RUN chmod +x /app/BuildConfig.sh RUN npm run build -EXPOSE 3000 -CMD ["/bin/bash", "-c", "/app/BuildConfig.sh && npm start"] \ No newline at end of file +FROM nginx:stable-alpine AS production-stage + +RUN apk add --no-cache bash + +WORKDIR /app +COPY package*.json ./ + +COPY --from=build-stage /app/dist /usr/share/nginx/html +COPY --from=build-stage /app/public/icons /usr/share/nginx/html/icons +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY BuildConfig.sh /docker-entrypoint.d/10-build-config.sh +RUN chmod a+x /docker-entrypoint.d/10-build-config.sh +EXPOSE $FRONTEND_PORT + +CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..52d58bc --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# Hangman Lab Frontend + +This project serves as a lightweight frontend solution for personal websites, designed to work seamlessly with Keycloak for authentication and authorization. It provides an easy-to-use interface for managing and publishing markdown files, allowing users to maintain their personal content effortlessly. + +## Table of Contents + +- [Features](#features) +- [Technologies Used](#technologies-used) +- [Installation](#installation) +- [Configuration](#configuration) +- [Development](#development) +- [Building for Production](#building-for-production) +- [Docker Deployment](#docker-deployment) +- [License](#license) + +## Features + +- **User Authentication**: Secure login and logout functionalities using **Keycloak** and **OpenID Connect (OIDC)**. +- **Markdown Management**: Create, edit, and view markdown files with live preview and syntax highlighting for a streamlined content creation experience. +- **Docker Support**: Containerized setup for easy deployment and scalability. + + +## Technologies Used + +This project uses the following open-source libraries, all of which are licensed under the MIT License: + +- [Bulma](https://bulma.io/) (MIT) +- [Katex](https://katex.org/) (MIT) +- [oidc-client-ts](https://github.com/authts/oidc-client-ts) (Apache-2.0) +- [React](https://reactjs.org/) (MIT) +- [React-DOM](https://reactjs.org/) (MIT) +- [React-Markdown](https://github.com/remarkjs/react-markdown) (MIT) +- [React-Query](https://react-query-v3.tanstack.com/) (MIT) +- [React-Router-DOM](https://reactrouter.com/) (MIT) +- [React-Syntax-Highlighter](https://github.com/react-syntax-highlighter/react-syntax-highlighter) (MIT) +- [Rehype-Katex](https://github.com/remarkjs/remark-math/tree/main/packages/rehype-katex) (MIT) +- [Rehype-Raw](https://github.com/rehypejs/rehype-raw) (MIT) +- [Remark-Math](https://github.com/remarkjs/remark-math) (MIT) + +The development dependencies (e.g., Babel, Webpack, and loaders) are also licensed under the MIT License. + +## Installation +### Prerequisites +- **Node.js** (v14.x or higher) +- **npm** (v6.x or higher) or **Yarn** +- **Docker** (optional, for containerized deployment) +- **Keycloak Server**: Ensure you have access to a Keycloak server for authentication. + +### Steps + +1. **Clone the Repository** + + ```bash + git clone https://git.hangman-lab.top/hzhang/HangmanLab.Frontend.git + cd HangmanLab.Frontend + ``` + +2. **Install Dependencies** + + Using npm: + + ```bash + npm install + ``` + + Or using Yarn: + + ```bash + yarn install + ``` + +3. **Configure environment variables** + + See Configuration[#configuration] + +4. **BuildConfig.sh** + + ```bash + chmod +x BuildConfig + ./BuildConfig.sh + ``` + +## Configuration +Set the following environment variables before running BuildConfig.sh + +### Environment Variables +- `BACKEND_HOST`: URL of the backend server (default: `http://localhost:5000`) +- `FRONTEND_HOST`: URL of the frontend server (default: `http://localhost:3000`) +- `KC_CLIENT_ID`: Keycloak client ID +- `KC_HOST`: Keycloak server URL +- `KC_REALM`: Keycloak realm + + +## Development + +### Running the Development Server + +Start the development server with hot reloading: + +```bash +npm start +``` + +Or using Yarn: + +```bash +yarn start +``` + +The application will be accessible at `http://localhost:3000` by default. + + +## Docker Deployment + +### Image +Pull the latest Docker image from the repository: +```bash +docker pull git.hangman-lab.top/hzhang/hangman-lab-frontend:latest +``` +### Building the docker Image +```bash +docker build -t hangman-lab-frontend:latest . +``` +### Running the Docker Container +Ensure your backend service (e.g., running at http://localhost:5000) is up and accessible. Then, run the Docker container: +```bash +docker run -d -p 80:80 --name hangman-lab-frontend hangman-lab-frontend:latest +``` + +#### Note: +- The container listens on port 80. Adjust the port mapping (-p) as needed. +- Make sure to set the appropriate environment variables either in the Dockerfile or via Docker environment variable options. +## License +[MIT][license] © [hzhang][author] + + +[author]: https://hangman-lab.top +[license]: license \ No newline at end of file diff --git a/licence b/licence new file mode 100644 index 0000000..d78261e --- /dev/null +++ b/licence @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) hzhang + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +'Software'), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..6949e9f --- /dev/null +++ b/nginx.conf @@ -0,0 +1,13 @@ +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html; + location / { + try_files $uri $uri/ /index.html; + } + location /icons/ { + try_files $uri =404; + } + error_page 404 /index.html; +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 53dc5c3..51f1ef4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@babel/preset-react": "^7.25.9", "babel-loader": "^9.2.1", "css-loader": "^7.1.2", + "dotenv-webpack": "^8.1.0", "html-webpack-plugin": "^5.6.3", "sass": "^1.81.0", "sass-loader": "^16.0.3", @@ -3611,6 +3612,39 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", + "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/dotenv-defaults": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dotenv-defaults/-/dotenv-defaults-2.0.2.tgz", + "integrity": "sha512-iOIzovWfsUHU91L5i8bJce3NYK5JXeAwH50Jh6+ARUdLiiGlYWfGw6UkzsYqaXZH/hjE/eCd/PlfM/qqyK0AMg==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0" + } + }, + "node_modules/dotenv-webpack": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/dotenv-webpack/-/dotenv-webpack-8.1.0.tgz", + "integrity": "sha512-owK1JcsPkIobeqjVrk6h7jPED/W6ZpdFsMPR+5ursB7/SdgDyO+VzAU+szK8C8u3qUhtENyYnj8eyXMR5kkGag==", + "dev": true, + "dependencies": { + "dotenv-defaults": "^2.0.2" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "webpack": "^4 || ^5" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", diff --git a/package.json b/package.json index 2137cb9..7e7dcff 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@babel/preset-react": "^7.25.9", "babel-loader": "^9.2.1", "css-loader": "^7.1.2", + "dotenv-webpack": "^8.1.0", "html-webpack-plugin": "^5.6.3", "sass": "^1.81.0", "sass-loader": "^16.0.3", diff --git a/public/icons/email.png b/public/icons/email.png new file mode 100644 index 0000000..71452e7 Binary files /dev/null and b/public/icons/email.png differ diff --git a/public/icons/git.png b/public/icons/git.png new file mode 100644 index 0000000..6f6bd97 Binary files /dev/null and b/public/icons/git.png differ diff --git a/public/icons/linkedin.png b/public/icons/linkedin.png new file mode 100644 index 0000000..2f8cb5f Binary files /dev/null and b/public/icons/linkedin.png differ diff --git a/src/App.css b/src/App.css index 18a6ab5..7c66043 100644 --- a/src/App.css +++ b/src/App.css @@ -7,10 +7,11 @@ .content-container { display: flex; flex: 1; + overflow: hidden; } .main-content { flex: 1; - padding: 1rem; + padding: 1rem 1rem 100px 1rem; overflow-y: auto; } \ No newline at end of file diff --git a/src/App.js b/src/App.js index 189c2f5..21b2637 100644 --- a/src/App.js +++ b/src/App.js @@ -5,11 +5,12 @@ import SideNavigation from "./components/Navigations/SideNavigation"; import MarkdownContent from "./components/Markdowns/MarkdownContent"; import MarkdownEditor from "./components/Markdowns/MarkdownEditor"; import "./App.css"; -import Callback from "./Callback"; -import config from "./config"; +import Callback from "./components/KeycloakCallbacks/Callback"; +import Footer from "./components/Footer"; +import PopupCallback from "./components/KeycloakCallbacks/PopupCallback"; +import SilentCallback from "./components/KeycloakCallbacks/SilentCallback"; const App = () => { - console.log(config) return (
@@ -22,14 +23,17 @@ const App = () => { } /> } /> TEST}> - }> - }> + } /> + } /> + } /> + } />
+