merge with main
This commit is contained in:
commit
f906d5fdce
16 changed files with 413 additions and 52 deletions
26
.dockerignore
Normal file
26
.dockerignore
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# flyctl launch added from .gitignore
|
||||
# Logs
|
||||
**\logs
|
||||
**\*.log
|
||||
**\npm-debug.log*
|
||||
**\yarn-debug.log*
|
||||
**\yarn-error.log*
|
||||
**\pnpm-debug.log*
|
||||
**\lerna-debug.log*
|
||||
|
||||
**\node_modules
|
||||
**\dist
|
||||
**\dist-ssr
|
||||
**\*.local
|
||||
|
||||
# Editor directories and files
|
||||
**\.vscode\*
|
||||
!**\.vscode\extensions.json
|
||||
**\.idea
|
||||
**\.DS_Store
|
||||
**\*.suo
|
||||
**\*.ntvs*
|
||||
**\*.njsproj
|
||||
**\*.sln
|
||||
**\*.sw?
|
||||
fly.toml
|
||||
18
.github/workflows/fly-deploy.yml
vendored
Normal file
18
.github/workflows/fly-deploy.yml
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# See https://fly.io/docs/app-guides/continuous-deployment-with-github-actions/
|
||||
|
||||
name: Fly Deploy
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
deploy:
|
||||
name: Deploy app
|
||||
runs-on: ubuntu-latest
|
||||
concurrency: deploy-group # optional: ensure only one action runs at a time
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: superfly/flyctl-actions/setup-flyctl@master
|
||||
- run: flyctl deploy --remote-only
|
||||
env:
|
||||
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
|
||||
27
Dockerfile
Normal file
27
Dockerfile
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Build Stage
|
||||
FROM node:18 AS build
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Serve Stage
|
||||
FROM nginx:stable-alpine
|
||||
|
||||
# Copy built React files into nginx public folder
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
# Remove default nginx config
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Add your own nginx config
|
||||
COPY nginx.conf /etc/nginx/conf.d
|
||||
|
||||
# Expose port 80
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
42
fly.toml
Normal file
42
fly.toml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# fly.toml app configuration file generated for bytecamp-web on 2025-04-21T13:40:11-07:00
|
||||
#
|
||||
# See https://fly.io/docs/reference/configuration/ for information about how to use this file.
|
||||
#
|
||||
|
||||
app = 'bytecamp-web'
|
||||
primary_region = 'sea'
|
||||
|
||||
[build]
|
||||
|
||||
[env]
|
||||
PORT = '8080'
|
||||
|
||||
[http_service]
|
||||
internal_port = 80
|
||||
force_https = true
|
||||
auto_stop_machines = 'stop'
|
||||
auto_start_machines = true
|
||||
min_machines_running = 0
|
||||
processes = ['app']
|
||||
|
||||
[[services]]
|
||||
protocol = 'tcp'
|
||||
internal_port = 8080
|
||||
|
||||
[[services.ports]]
|
||||
port = 80
|
||||
handlers = ['http']
|
||||
|
||||
[[services.ports]]
|
||||
port = 443
|
||||
handlers = ['tls', 'http']
|
||||
|
||||
[[services.tcp_checks]]
|
||||
interval = '10s'
|
||||
timeout = '2s'
|
||||
grace_period = '5s'
|
||||
|
||||
[[vm]]
|
||||
memory = '1gb'
|
||||
cpu_kind = 'shared'
|
||||
cpus = 1
|
||||
11
nginx.conf
Normal file
11
nginx.conf
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri /index.html;
|
||||
}
|
||||
}
|
||||
BIN
public/images/grid-background.jpg
Normal file
BIN
public/images/grid-background.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 252 KiB |
|
|
@ -17,6 +17,9 @@ const Header = () => {
|
|||
<li>
|
||||
<Link to="/login">Login</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/assignment">Assignment</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,41 @@
|
|||
import React from 'react'
|
||||
import '../scss/styles.scss'
|
||||
import '../scss/components/_navbar.scss'
|
||||
import React from "react";
|
||||
import "../scss/styles.scss";
|
||||
import "../scss/components/_navbar.scss";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
const Navbar = () => {
|
||||
return (
|
||||
<nav className="navbar">
|
||||
<div className="navbar__logo">MyApp</div>
|
||||
<ul className="navbar__links">
|
||||
<li><a href="/" className="navbar__link">Home</a></li>
|
||||
<li><a href="/notebook" className="navbar__link">NoteBook</a></li>
|
||||
<li><a href="/assignment" className="navbar__link">Assignment</a></li>
|
||||
<li><a href="/editor" className="navbar__link">Editor</a></li>
|
||||
<li>
|
||||
<Link to="/" className="navbar__link">
|
||||
Home
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/notebook" className="navbar__link">
|
||||
NoteBook
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/assignment" className="navbar__link">
|
||||
Assignment
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/editor" className="navbar__link">
|
||||
Editor
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/login" className="navbar__link">
|
||||
Login
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export default Navbar
|
||||
export default Navbar;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,10 @@ import "./scss/styles.scss";
|
|||
import Navbar from "./components/Navbar";
|
||||
import Hero from "./components/Hero";
|
||||
import Services from "./components/Services";
|
||||
import Header from "./components/Header";
|
||||
|
||||
createRoot(document.getElementById("root")).render(
|
||||
<StrictMode>
|
||||
|
||||
<AppRouter />
|
||||
|
||||
</StrictMode>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const LoginPage = () => {
|
|||
const [type, setType] = useState("signIn");
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Login / Sign Up";
|
||||
document.title = "Login / Instructor";
|
||||
}, []);
|
||||
|
||||
const handleOnClick = (text) => {
|
||||
|
|
@ -23,7 +23,7 @@ const LoginPage = () => {
|
|||
return (
|
||||
<main className="login-page">
|
||||
<section>
|
||||
<h2>Sign In/Sign Up</h2>
|
||||
<h2>Student/Instructor</h2>
|
||||
<div className={containerClass} id="container">
|
||||
<SignUpForm />
|
||||
<SignInForm />
|
||||
|
|
@ -31,26 +31,24 @@ const LoginPage = () => {
|
|||
<div className="overlay">
|
||||
<div className="overlay-panel overlay-left">
|
||||
<h1>Welcome Back!</h1>
|
||||
<p>
|
||||
To keep connected with us please login with your personal info
|
||||
</p>
|
||||
<p>Please login with your personal info</p>
|
||||
<button
|
||||
className="ghost"
|
||||
id="signIn"
|
||||
onClick={() => handleOnClick("signIn")}
|
||||
>
|
||||
Sign In
|
||||
Student
|
||||
</button>
|
||||
</div>
|
||||
<div className="overlay-panel overlay-right">
|
||||
<h1>Hello, Friend!</h1>
|
||||
<p>Enter your personal details and start journey with us</p>
|
||||
<h1>Hello, Instructor!</h1>
|
||||
<p>Please enter your personal details here</p>
|
||||
<button
|
||||
className="ghost"
|
||||
id="signUp"
|
||||
onClick={() => handleOnClick("signUp")}
|
||||
>
|
||||
Sign Up
|
||||
Instructor
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,22 +31,16 @@ function SignInForm() {
|
|||
return (
|
||||
<div className="form-container sign-in-container">
|
||||
<form onSubmit={handleOnSubmit}>
|
||||
<h1>Sign in</h1>
|
||||
<div className="social-container">
|
||||
<a href="#" className="social">
|
||||
<i className="fab fa-facebook-f" />
|
||||
</a>
|
||||
<h1>Student</h1>
|
||||
{/* <div className="social-container">
|
||||
<a href="#" className="social">
|
||||
<i className="fab fa-google-plus-g" />
|
||||
</a>
|
||||
<a href="#" className="social">
|
||||
<i className="fab fa-linkedin-in" />
|
||||
</a>
|
||||
</div>
|
||||
<span>or use your account</span>
|
||||
</div> */}
|
||||
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Email"
|
||||
placeholder="Student Name"
|
||||
name="email"
|
||||
value={state.email}
|
||||
onChange={handleChange}
|
||||
|
|
@ -58,7 +52,7 @@ function SignInForm() {
|
|||
value={state.password}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<a href="#">Forgot your password?</a>
|
||||
|
||||
<button>Sign In</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ function SignUpForm() {
|
|||
|
||||
const { name, email, password } = state;
|
||||
alert(
|
||||
`You are sign up with name: ${name} email: ${email} and password: ${password}`
|
||||
`You are signed in with name: ${name} email: ${email} and password: ${password}`
|
||||
);
|
||||
|
||||
for (const key in state) {
|
||||
|
|
@ -29,20 +29,18 @@ function SignUpForm() {
|
|||
}
|
||||
};
|
||||
|
||||
const googleAuth = () => {
|
||||
window.open("https://byte-camp-auth-service.fly.dev/auth/google", "_self");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="form-container sign-up-container">
|
||||
<form onSubmit={handleOnSubmit}>
|
||||
<h1>Create Account</h1>
|
||||
<h1>Instructor</h1>
|
||||
<div className="social-container">
|
||||
<a href="#" className="social">
|
||||
<i className="fab fa-facebook-f" />
|
||||
</a>
|
||||
<a href="#" className="social">
|
||||
<a href="#" className="social" onClick={googleAuth}>
|
||||
<i className="fab fa-google-plus-g" />
|
||||
</a>
|
||||
<a href="#" className="social">
|
||||
<i className="fab fa-linkedin-in" />
|
||||
</a>
|
||||
</div>
|
||||
<span>or use your email for registration</span>
|
||||
<input
|
||||
|
|
@ -66,7 +64,7 @@ function SignUpForm() {
|
|||
onChange={handleChange}
|
||||
placeholder="Password"
|
||||
/>
|
||||
<button>Sign Up</button>
|
||||
<button>Sign in</button>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import HomePage from "../pages/HomePage";
|
|||
import LoginPage from "../pages/LoginPage";
|
||||
import PageCodeEditor from "../pages/CodeEditor";
|
||||
import PageNotFound from "../pages/PageNotFound";
|
||||
import AssignmentPage from "../pages/AssignmentPage";
|
||||
import Hero from "../components/Hero";
|
||||
import Navbar from "../components/Navbar";
|
||||
import Services from "../components/Services";
|
||||
|
|
@ -20,10 +21,8 @@ const AppRouter = () => {
|
|||
return (
|
||||
<BrowserRouter>
|
||||
<div className="wrapper">
|
||||
{/* <Header /> */}
|
||||
<Navbar />
|
||||
<Routes>
|
||||
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
|
|
@ -43,7 +42,7 @@ const AppRouter = () => {
|
|||
/>
|
||||
<Route path="login" element={<LoginPage />} />
|
||||
<Route
|
||||
path="editor"
|
||||
path="/editor"
|
||||
element={
|
||||
<ProtectedRoute>
|
||||
<PageCodeEditor />
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
// .login-page {
|
||||
// min-height: 100vh;
|
||||
// display: flex;
|
||||
// justify-content: center;
|
||||
// align-items: center;
|
||||
|
||||
// background-image: url("../../../public/images/grid-background.png");
|
||||
// background-size: cover;
|
||||
// background-position: center;
|
||||
// background-repeat: no-repeat;
|
||||
// background-attachment: fixed;
|
||||
|
||||
// section {
|
||||
// width: 100%;
|
||||
// max-width: 800px;
|
||||
// padding: 20px;
|
||||
// }
|
||||
// }
|
||||
.App {
|
||||
font-family: sans-serif;
|
||||
text-align: center;
|
||||
|
|
@ -10,7 +28,12 @@
|
|||
}
|
||||
|
||||
body {
|
||||
background: #f6f5f7;
|
||||
background: transparent;
|
||||
background-image: url("../../../public/images/grid-background.jpg");
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
|
@ -27,6 +50,8 @@ h1 {
|
|||
|
||||
h2 {
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
p {
|
||||
|
|
@ -227,8 +252,8 @@ input {
|
|||
justify-content: center;
|
||||
align-items: center;
|
||||
margin: 0 5px;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
footer {
|
||||
|
|
|
|||
198
src/scss/page/assignment.scss
Normal file
198
src/scss/page/assignment.scss
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
// Assignment Page Styling
|
||||
|
||||
.assignment-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 2rem;
|
||||
|
||||
section {
|
||||
width: 100%;
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.assignment-header {
|
||||
margin-bottom: 2rem;
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
padding-bottom: 1rem;
|
||||
|
||||
h2 {
|
||||
font-size: 3rem;
|
||||
margin-bottom: 1rem;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.due-date {
|
||||
color: #c6c6c6;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
.assignment-container {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
padding: 2rem;
|
||||
|
||||
.assignment-info {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
h3 {
|
||||
font-size: 1.4rem;
|
||||
margin-bottom: 0.5rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.files-count {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.submission-note {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.file-upload-section {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
.upload-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.file-upload-btn,
|
||||
.record-audio-btn,
|
||||
.record-video-btn {
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 0.6rem 1rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
transition: all 0.2s ease;
|
||||
color: #333;
|
||||
|
||||
&:hover {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.files-list {
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 6px;
|
||||
padding: 1rem;
|
||||
|
||||
h4 {
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
|
||||
.file-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex-grow: 1;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
color: #777;
|
||||
margin: 0 1rem;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.remove-file-btn {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: #ff5252;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
padding: 0.3rem 0.6rem;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.comments-section {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
h4 {
|
||||
margin-bottom: 0.8rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 0.8rem;
|
||||
font-family: inherit;
|
||||
resize: vertical;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: #4a90e2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.submission-buttons {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
|
||||
.submit-btn,
|
||||
.cancel-btn {
|
||||
padding: 0.7rem 1.5rem;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
background-color: #4a90e2;
|
||||
color: white;
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #3a7bc8;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: #a0c3e8;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
background-color: transparent;
|
||||
border: 1px solid #ddd;
|
||||
color: #666;
|
||||
|
||||
&:hover {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
@use "./page//home";
|
||||
@use "./page//login";
|
||||
@use "./page/code_editor";
|
||||
@use "./page/assignment";
|
||||
|
||||
// Utilities
|
||||
@use "./utilities/utility-classes";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue