improve: add production stage

This commit is contained in:
h z
2024-12-09 07:01:22 +00:00
parent 0e6fd8409a
commit ba69541a7b
29 changed files with 616 additions and 92 deletions

97
src/components/Footer.css Normal file
View File

@@ -0,0 +1,97 @@
.footer {
background-color: #333;
color: #fff;
padding: 1rem;
position: fixed;
width: 100%;
display: flex;
bottom: 0;
flex-direction: column;
justify-content: space-between;
align-items: center;
box-sizing: border-box;
overflow: visible;
max-height: 5rem;
transition: max-height 0.3s ease;
}
.footer.expanded {
max-height: 20rem;
}
.footer-details{
opacity: 0;
max-height: 0;
overflow: hidden;
transition: opacity 0.3s ease, max-height 0.3s ease;
}
.footer-details.expanded {
opacity: 1;
max-height: 15rem;
}
.footer-content {
margin-bottom: auto;
text-align: center;
}
.footer-icons {
display: flex;
flex-direction: column;
gap: 1rem;
align-items: flex-end;
margin-right: 1rem;
}
.footer-icon {
width: 40px;
height: 40px;
transition: transform 0.2s;
}
.footer-icon:hover {
transform: scale(1.2);
}
.footer-icons a {
display: flex;
align-items: center;
gap: 0.5rem;
color: #00d1b2;
text-decoration: none;
}
.footer-icons a:hover {
color: #00a6a2;
}
.toggle-button {
width: 2rem;
height: 2rem;
border-radius: 50%;
background-color: #007bff;
color: white;
border: none;
font-size: 1.2rem;
font-weight: bold;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
transition: transform 0.2s ease, background-color 0.3s ease;
position: absolute;
top: -1rem;
left: 50%;
transform: translateX(-50%);
}
.toggle-button:hover {
background-color: #0056b3;
transform: scale(1.1) translateX(-50%);
}
.toggle-button:focus {
outline: none;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.5);
}

78
src/components/Footer.js Normal file
View File

@@ -0,0 +1,78 @@
import React from "react";
import "./Footer.css";
const Footer = () => {
const [isExpanded, setIsExpanded] = React.useState(false);
const [isVisible, setIsVisible] = React.useState(false);
const toggleExpand = () => {
if(!isExpanded) {
setIsVisible(true);
}
setIsExpanded((prev) => !prev);
};
const onTransitionEnd = () => {
if(!isExpanded) {
setIsVisible(false);
}
};
return (
<footer className={`footer ${isExpanded ? "expanded" : ""}`}>
<button
className="toggle-button"
onClick={toggleExpand}
type="button"
>
{isExpanded ? "↓" : "↑"}
</button>
<div className={`footer-content`}>
<p>&copy; {new Date().getFullYear()} Hangman Lab. All rights reserved.</p>
{
isVisible && (
<div
className={`footer-details ${isExpanded ? "expanded" : ""}`}
onTransitionEnd={onTransitionEnd}
>
<div className="footer-icons">
<a
href="https://www.linkedin.com/in/zhhrozhh/"
target="_blank"
rel="noopener noreferrer"
>
<img
src="/icons/linkedin.png"
alt="LinkedIn"
className="footer-icon"
/>
LinkedIn
</a>
<a
href="https://git.hangman-lab.top/hzhang/HangmanLab"
target="_blank"
rel="noopener noreferrer"
>
<img
src="/icons/git.png"
alt="GitHub"
className="footer-icon"
/>
GitHub
</a>
<a href="mailto:hzhang@hangman-lab.top">
<img
src="/icons/email.png"
alt="Email"
className="footer-icon"
/>
Email
</a>
</div>
</div>
)
}
</div>
</footer>
);
};
export default Footer;

View File

@@ -0,0 +1,19 @@
import React, {useContext, useEffect} from "react";
import { UserManager } from "oidc-client-ts";
import {ConfigContext} from "../../ConfigProvider";
const Callback = () => {
const config = useContext(ConfigContext).config;
useEffect(() => {
const userManager = new UserManager(config.OIDC_CONFIG);
userManager.signinRedirectCallback()
.then(() => {
window.location.href = "/";
});
}, []);
return <div>Logging in...</div>;
};
export default Callback;

View File

@@ -0,0 +1,24 @@
import React, { useEffect, useContext } from "react";
import { UserManager } from "oidc-client-ts";
import {ConfigContext} from "../../ConfigProvider";
const PopupCallback = () => {
const { config } = useContext(ConfigContext);
useEffect(() => {
const userManager = new UserManager(config.OIDC_CONFIG);
userManager.signinPopupCallback()
.then(() => {
window.close();
})
.catch((err) => {
console.error("Popup callback error:", err);
window.close();
});
}, [config]);
return <div>Processing...</div>;
};
export default PopupCallback;

View File

@@ -0,0 +1,21 @@
import React, { useEffect, useContext } from "react";
import { UserManager } from "oidc-client-ts";
import { ConfigContext } from "../../ConfigProvider";
const SilentCallback = () => {
const { config } = useContext(ConfigContext);
useEffect(() => {
const userManager = new UserManager(config.OIDC_CONFIG);
userManager.signinSilentCallback()
.then(() => {
})
.catch((err) => {
console.error("Silent callback error:", err);
});
}, [config]);
return <div>Renew...</div>;
};
export default SilentCallback;

View File

@@ -80,7 +80,6 @@
font-size: 1.2rem;
}
code {
font-family: 'Courier New', Courier, monospace;
background-color: #f4f4f4;

View File

@@ -32,18 +32,18 @@ pre {
.markdown-preview ul,
.markdown-preview ol {
padding-left: 1.5rem; /* 设置左侧缩进 */
margin-bottom: 1rem; /* 每个列表的底部间距 */
padding-left: 1.5rem;
margin-bottom: 1rem;
}
.markdown-preview ul {
list-style-type: disc; /* 确保无序列表使用圆点 */
list-style-type: disc;
}
.markdown-preview ol {
list-style-type: decimal; /* 确保有序列表使用数字 */
list-style-type: decimal;
}
.markdown-preview li {
margin-bottom: 0.5rem; /* 列表项之间的间距 */
margin-bottom: 0.5rem;
}

View File

@@ -1,9 +1,10 @@
/* src/components/SideNavigation.css */
.menu {
border: 1px solid #ddd;
border-radius: 8px;
padding: 1rem;
background-color: #f9f9f9;
height: 100%;
overflow-y: auto;
}
.menu-label {

View File

@@ -2,10 +2,10 @@ import PermissionGuard from "../PermissionGuard";
import PathNode from "./PathNode";
import "./SideNavigation.css";
import {useDeletePath, usePaths, useUpdatePath} from "../../utils/path-queries";
import React from 'react';
const SideNavigation = () => {
const {data: paths, isLoading, error} = usePaths(1);
const {data: paths, isLoading, error } = usePaths(1);
const deletePath = useDeletePath();
const updatePath = useUpdatePath();
@@ -20,7 +20,7 @@ const SideNavigation = () => {
};
const handleSave = (id, newName) => {
updatePath.mutate({ id, data: {name: newName}} , {
updatePath.mutate({ id, data: {name: newName }} , {
onError: (err) => {
alert("Failed to update path");
}

View File

@@ -1,11 +1,10 @@
// src/components/PathManager.js
import React, { useEffect, useState, useRef } from "react";
import React, {useEffect, useState, useRef, useContext} from "react";
import { useCreatePath, usePaths } from "../utils/path-queries";
import { useQueryClient } from "react-query";
import "./PathManager.css";
import {fetch_} from "../utils/request-utils";
import config from "../config";
import {ConfigContext} from "../ConfigProvider";
const PathManager = ({ currentPathId = 1, onPathChange }) => {
const [currentPath, setCurrentPath] = useState([{ name: "Root", id: 1 }]);
@@ -17,6 +16,7 @@ const PathManager = ({ currentPathId = 1, onPathChange }) => {
const queryClient = useQueryClient();
const { data: subPaths, isLoading: isSubPathsLoading, error: subPathsError } = usePaths(currentPathId);
const createPath = useCreatePath();
const config = useContext(ConfigContext).config;
const buildPath = async (pathId) => {
const path = [];